Add post drafts

This commit is contained in:
Shadowfacts 2018-10-22 22:09:11 -04:00
parent c1bfc6d3d9
commit df6976df2f
Signed by untrusted user: shadowfacts
GPG Key ID: 94A5AB95422746E5
12 changed files with 379 additions and 14 deletions

View File

@ -61,6 +61,11 @@
D621544B21682AD30003D87D /* TabTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621544A21682AD30003D87D /* TabTableViewCell.swift */; }; D621544B21682AD30003D87D /* TabTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D621544A21682AD30003D87D /* TabTableViewCell.swift */; };
D621544D21682AD90003D87D /* TabTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D621544C21682AD90003D87D /* TabTableViewCell.xib */; }; D621544D21682AD90003D87D /* TabTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D621544C21682AD90003D87D /* TabTableViewCell.xib */; };
D627FF74217BBC9700CC0648 /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF73217BBC9700CC0648 /* AppRouter.swift */; }; D627FF74217BBC9700CC0648 /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF73217BBC9700CC0648 /* AppRouter.swift */; };
D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF75217E923E00CC0648 /* DraftsManager.swift */; };
D627FF79217E950100CC0648 /* DraftsTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D627FF78217E950100CC0648 /* DraftsTableViewController.xib */; };
D627FF7B217E951500CC0648 /* DraftsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF7A217E951500CC0648 /* DraftsTableViewController.swift */; };
D627FF7D217E958900CC0648 /* DraftTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D627FF7C217E958900CC0648 /* DraftTableViewCell.xib */; };
D627FF7F217E95E000CC0648 /* DraftTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF7E217E95E000CC0648 /* DraftTableViewCell.swift */; };
D6289E84217B795D0003D1D7 /* LargeImageViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */; }; D6289E84217B795D0003D1D7 /* LargeImageViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */; };
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2421217AA7E1005076CC /* UserActivityManager.swift */; }; D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2421217AA7E1005076CC /* UserActivityManager.swift */; };
D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */; }; D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */; };
@ -249,6 +254,11 @@
D621544A21682AD30003D87D /* TabTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabTableViewCell.swift; sourceTree = "<group>"; }; D621544A21682AD30003D87D /* TabTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabTableViewCell.swift; sourceTree = "<group>"; };
D621544C21682AD90003D87D /* TabTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TabTableViewCell.xib; sourceTree = "<group>"; }; D621544C21682AD90003D87D /* TabTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TabTableViewCell.xib; sourceTree = "<group>"; };
D627FF73217BBC9700CC0648 /* AppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = "<group>"; }; D627FF73217BBC9700CC0648 /* AppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = "<group>"; };
D627FF75217E923E00CC0648 /* DraftsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsManager.swift; sourceTree = "<group>"; };
D627FF78217E950100CC0648 /* DraftsTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DraftsTableViewController.xib; sourceTree = "<group>"; };
D627FF7A217E951500CC0648 /* DraftsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsTableViewController.swift; sourceTree = "<group>"; };
D627FF7C217E958900CC0648 /* DraftTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DraftTableViewCell.xib; sourceTree = "<group>"; };
D627FF7E217E95E000CC0648 /* DraftTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftTableViewCell.swift; sourceTree = "<group>"; };
D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LargeImageViewController.xib; sourceTree = "<group>"; }; D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LargeImageViewController.xib; sourceTree = "<group>"; };
D62D2421217AA7E1005076CC /* UserActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityManager.swift; sourceTree = "<group>"; }; D62D2421217AA7E1005076CC /* UserActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityManager.swift; sourceTree = "<group>"; };
D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserActivity+Extensions.swift"; sourceTree = "<group>"; }; D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserActivity+Extensions.swift"; sourceTree = "<group>"; };
@ -481,6 +491,17 @@
path = Tab; path = Tab;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D627FF77217E94F200CC0648 /* Drafts */ = {
isa = PBXGroup;
children = (
D627FF78217E950100CC0648 /* DraftsTableViewController.xib */,
D627FF7A217E951500CC0648 /* DraftsTableViewController.swift */,
D627FF7C217E958900CC0648 /* DraftTableViewCell.xib */,
D627FF7E217E95E000CC0648 /* DraftTableViewCell.swift */,
);
path = Drafts;
sourceTree = "<group>";
};
D62D241E217AA46B005076CC /* Shortcuts */ = { D62D241E217AA46B005076CC /* Shortcuts */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -560,6 +581,7 @@
D641C787213DD862004B4513 /* Compose */ = { D641C787213DD862004B4513 /* Compose */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D627FF77217E94F200CC0648 /* Drafts */,
D6A5FAF0217B7E05003DB2D9 /* ComposeViewController.xib */, D6A5FAF0217B7E05003DB2D9 /* ComposeViewController.xib */,
D66362702136338600C9CBA2 /* ComposeViewController.swift */, D66362702136338600C9CBA2 /* ComposeViewController.swift */,
); );
@ -747,6 +769,7 @@
D6D4DDCF212518A000E1C4BB /* AppDelegate.swift */, D6D4DDCF212518A000E1C4BB /* AppDelegate.swift */,
D627FF73217BBC9700CC0648 /* AppRouter.swift */, D627FF73217BBC9700CC0648 /* AppRouter.swift */,
D64D0AAC2128D88B005A6F37 /* LocalData.swift */, D64D0AAC2128D88B005A6F37 /* LocalData.swift */,
D627FF75217E923E00CC0648 /* DraftsManager.swift */,
04DACE8D212CC7CC009840C4 /* ImageCache.swift */, 04DACE8D212CC7CC009840C4 /* ImageCache.swift */,
D6028B9A2150811100F223B9 /* MastodonCache.swift */, D6028B9A2150811100F223B9 /* MastodonCache.swift */,
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */, D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */,
@ -1007,6 +1030,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D641C779213CAC56004B4513 /* ActionNotificationTableViewCell.xib in Resources */, D641C779213CAC56004B4513 /* ActionNotificationTableViewCell.xib in Resources */,
D627FF7D217E958900CC0648 /* DraftTableViewCell.xib in Resources */,
D667E5E921349EE50057A976 /* ProfileHeaderTableViewCell.xib in Resources */, D667E5E921349EE50057A976 /* ProfileHeaderTableViewCell.xib in Resources */,
D6C693CD2161257B007D6A6D /* SilentActionPermissionCell.xib in Resources */, D6C693CD2161257B007D6A6D /* SilentActionPermissionCell.xib in Resources */,
D6D4DDDA212518A200E1C4BB /* LaunchScreen.storyboard in Resources */, D6D4DDDA212518A200E1C4BB /* LaunchScreen.storyboard in Resources */,
@ -1016,6 +1040,7 @@
D641C77B213CB017004B4513 /* FollowNotificationTableViewCell.xib in Resources */, D641C77B213CB017004B4513 /* FollowNotificationTableViewCell.xib in Resources */,
D6289E84217B795D0003D1D7 /* LargeImageViewController.xib in Resources */, D6289E84217B795D0003D1D7 /* LargeImageViewController.xib in Resources */,
D663626621360DD700C9CBA2 /* Preferences.storyboard in Resources */, D663626621360DD700C9CBA2 /* Preferences.storyboard in Resources */,
D627FF79217E950100CC0648 /* DraftsTableViewController.xib in Resources */,
D667E5E12134937B0057A976 /* StatusTableViewCell.xib in Resources */, D667E5E12134937B0057A976 /* StatusTableViewCell.xib in Resources */,
D6A5FAF1217B7E05003DB2D9 /* ComposeViewController.xib in Resources */, D6A5FAF1217B7E05003DB2D9 /* ComposeViewController.xib in Resources */,
D621544D21682AD90003D87D /* TabTableViewCell.xib in Resources */, D621544D21682AD90003D87D /* TabTableViewCell.xib in Resources */,
@ -1118,8 +1143,10 @@
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */, D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
D621544B21682AD30003D87D /* TabTableViewCell.swift in Sources */, D621544B21682AD30003D87D /* TabTableViewCell.swift in Sources */,
04DACE8E212CC7CC009840C4 /* ImageCache.swift in Sources */, 04DACE8E212CC7CC009840C4 /* ImageCache.swift in Sources */,
D627FF7B217E951500CC0648 /* DraftsTableViewController.swift in Sources */,
D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */, D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */,
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */, 04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */,
D627FF7F217E95E000CC0648 /* DraftTableViewCell.swift in Sources */,
D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */, D663626421360D2300C9CBA2 /* AvatarStyle.swift in Sources */,
D679C09F215850EF00DA27FE /* XCBActions.swift in Sources */, D679C09F215850EF00DA27FE /* XCBActions.swift in Sources */,
D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */, D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */,
@ -1143,6 +1170,7 @@
D627FF74217BBC9700CC0648 /* AppRouter.swift in Sources */, D627FF74217BBC9700CC0648 /* AppRouter.swift in Sources */,
D6C693FE2162FEEA007D6A6D /* UIViewController+Children.swift in Sources */, D6C693FE2162FEEA007D6A6D /* UIViewController+Children.swift in Sources */,
D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */, D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */,
D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */,
D663626821360E2C00C9CBA2 /* PreferencesTableViewController.swift in Sources */, D663626821360E2C00C9CBA2 /* PreferencesTableViewController.swift in Sources */,
D64F80E2215875CC00BEF393 /* XCBActionType.swift in Sources */, D64F80E2215875CC00BEF393 /* XCBActionType.swift in Sources */,
D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */, D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */,

View File

@ -48,6 +48,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
Preferences.save() Preferences.save()
DraftsManager.save()
} }
func applicationWillEnterForeground(_ application: UIApplication) { func applicationWillEnterForeground(_ application: UIApplication) {

View File

@ -81,6 +81,10 @@ class AppRouter {
return ComposeViewController(inReplyTo: inReplyToID, mentioningAcct: mentioningAcct, text: text, router: self) return ComposeViewController(inReplyTo: inReplyToID, mentioningAcct: mentioningAcct, text: text, router: self)
} }
func drafts() -> DraftsTableViewController {
return DraftsTableViewController()
}
func largeImage(_ image: UIImage, description: String?, sourceFrame: CGRect, sourceCornerRadius: CGFloat, transitioningDelegate: UIViewControllerTransitioningDelegate?) -> LargeImageViewController { func largeImage(_ image: UIImage, description: String?, sourceFrame: CGRect, sourceCornerRadius: CGFloat, transitioningDelegate: UIViewControllerTransitioningDelegate?) -> LargeImageViewController {
let vc = LargeImageViewController(image: image, description: description, sourceFrame: sourceFrame, sourceCornerRadius: sourceCornerRadius, router: self) let vc = LargeImageViewController(image: image, description: description, sourceFrame: sourceFrame, sourceCornerRadius: sourceCornerRadius, router: self)
vc.transitioningDelegate = transitioningDelegate vc.transitioningDelegate = transitioningDelegate

View File

@ -0,0 +1,72 @@
//
// DraftsManager.swift
// Tusker
//
// Created by Shadowfacts on 10/22/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import Foundation
class DraftsManager: Codable {
private(set) static var shared: DraftsManager = load()
private static var documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
private static var archiveURL = DraftsManager.documentsDirectory.appendingPathComponent("drafts").appendingPathExtension("plist")
static func save() {
let encoder = PropertyListEncoder()
let data = try? encoder.encode(shared)
try? data?.write(to: archiveURL, options: .noFileProtection)
}
static func load() -> DraftsManager {
let decoder = PropertyListDecoder()
if let data = try? Data(contentsOf: archiveURL),
let draftsManager = try? decoder.decode(DraftsManager.self, from: data) {
return draftsManager
}
return DraftsManager()
}
private init() {}
var drafts: [Draft] = []
var sorted: [Draft] {
return drafts.sorted(by: { $0.lastModified > $1.lastModified })
}
func create(text: String) {
drafts.append(Draft(text: text, lastModified: Date()))
}
func remove(_ draft: Draft) {
let index = drafts.firstIndex(of: draft)!
drafts.remove(at: index)
}
}
extension DraftsManager {
class Draft: Codable, Equatable {
let id: UUID
private(set) var text: String
private(set) var lastModified: Date
init(text: String, lastModified: Date) {
self.id = UUID()
self.text = text
self.lastModified = lastModified
}
func update(text: String) {
self.text = text
self.lastModified = Date()
}
static func ==(lhs: Draft, rhs: Draft) -> Bool {
return lhs.id == rhs.id
}
}
}

View File

@ -19,12 +19,12 @@ class Preferences: Codable {
static func save() { static func save() {
let encoder = PropertyListEncoder() let encoder = PropertyListEncoder()
let data = try? encoder.encode(shared) let data = try? encoder.encode(shared)
try? data?.write(to: Preferences.archiveURL, options: .noFileProtection) try? data?.write(to: archiveURL, options: .noFileProtection)
} }
static func load() -> Preferences { static func load() -> Preferences {
let decoder = PropertyListDecoder() let decoder = PropertyListDecoder()
if let data = try? Data(contentsOf: Preferences.archiveURL), if let data = try? Data(contentsOf: archiveURL),
let preferences = try? decoder.decode(Preferences.self, from: data) { let preferences = try? decoder.decode(Preferences.self, from: data) {
return preferences return preferences
} }
@ -41,6 +41,8 @@ class Preferences: Codable {
var defaultPostVisibility = Status.Visibility.public var defaultPostVisibility = Status.Visibility.public
var automaticallySaveDrafts = true
// MARK: - Advanced // MARK: - Advanced
var silentActions: [String: Permission] = [:] var silentActions: [String: Permission] = [:]

View File

@ -34,8 +34,13 @@ class ComposeViewController: UIViewController {
var scrolled = false var scrolled = false
var inReplyToID: String? var inReplyToID: String?
// TODO: cleanup this
var mentioningAcct: String? var mentioningAcct: String?
var text: String? var text: String?
var initialText: String?
var draft: DraftsManager.Draft?
// Weak so that if a new session is initiated (i.e. XCBManager.currentSession is changed) while the current one is in progress, this one will be released // Weak so that if a new session is initiated (i.e. XCBManager.currentSession is changed) while the current one is in progress, this one will be released
weak var xcbSession: XCBSession? weak var xcbSession: XCBSession?
@ -62,6 +67,7 @@ class ComposeViewController: UIViewController {
super.init(nibName: "ComposeViewController", bundle: nil) super.init(nibName: "ComposeViewController", bundle: nil)
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelPressed)) navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelPressed))
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Drafts", style: .plain, target: self, action: #selector(draftsPressed))
} }
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
@ -117,6 +123,8 @@ class ComposeViewController: UIViewController {
statusTextView.text += text statusTextView.text += text
} }
initialText = statusTextView.text.trimmingCharacters(in: .whitespacesAndNewlines)
updateCharactersRemaining() updateCharactersRemaining()
updatePlaceholder() updatePlaceholder()
@ -273,6 +281,11 @@ class ComposeViewController: UIViewController {
guard case let .success(status, _) = response else { fatalError() } guard case let .success(status, _) = response else { fatalError() }
self.status = status self.status = status
MastodonCache.add(status: status) MastodonCache.add(status: status)
if let draft = self.draft {
DraftsManager.shared.remove(draft)
}
DispatchQueue.main.async { DispatchQueue.main.async {
self.progressView.step() self.progressView.step()
self.dismiss(animated: true) self.dismiss(animated: true)
@ -296,11 +309,53 @@ class ComposeViewController: UIViewController {
statusTextView.endEditing(false) statusTextView.endEditing(false)
} }
@objc func cancelPressed() { func saveDraft() {
if let draft = draft {
draft.update(text: statusTextView.text)
} else {
DraftsManager.shared.create(text: statusTextView.text)
}
}
func close() {
dismiss(animated: true) dismiss(animated: true)
xcbSession?.complete(with: .cancel) xcbSession?.complete(with: .cancel)
} }
@objc func cancelPressed() {
guard statusTextView.text.trimmingCharacters(in: .whitespacesAndNewlines) != initialText else {
close()
return
}
if Preferences.shared.automaticallySaveDrafts {
saveDraft()
close()
return
}
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Save draft", style: .default, handler: { (_) in
self.saveDraft()
self.close()
}))
alert.addAction(UIAlertAction(title: "Delete draft", style: .destructive, handler: { (_) in
if let draft = self.draft {
DraftsManager.shared.remove(draft)
}
self.close()
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in
}))
router.present(alert, animated: true)
}
@objc func draftsPressed() {
let drafts = router.drafts()
drafts.delegate = self
router.present(UINavigationController(rootViewController: drafts), animated: true)
}
} }
extension ComposeViewController: UITextFieldDelegate { extension ComposeViewController: UITextFieldDelegate {
@ -340,3 +395,14 @@ extension ComposeViewController: ComposeMediaViewDelegate {
present(alertController, animated: true) present(alertController, animated: true)
} }
} }
extension ComposeViewController: DraftsTableViewControllerDelegate {
func draftSelectionCanceled() {
}
func draftSelected(_ draft: DraftsManager.Draft) {
self.draft = draft
statusTextView.text = draft.text
updatePlaceholder()
}
}

View File

@ -0,0 +1,21 @@
//
// DraftsTableViewCell.swift
// Tusker
//
// Created by Shadowfacts on 10/22/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import UIKit
class DraftTableViewCell: UITableViewCell {
@IBOutlet weak var contentLabel: UILabel!
@IBOutlet weak var lastModifiedLabel: UILabel!
func updateUI(for draft: DraftsManager.Draft) {
contentLabel.text = draft.text
lastModifiedLabel.text = draft.lastModified.timeAgoString()
}
}

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.23.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.16.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8eA-yd-rBp">
<rect key="frame" x="16" y="11.5" width="302" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2m" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D2X-9O-iQw">
<rect key="frame" x="334" y="11.5" width="25" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="8eA-yd-rBp" firstAttribute="leading" secondItem="KVi-jA-AET" secondAttribute="leadingMargin" id="Doq-4D-KSu"/>
<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="centerY" secondItem="KVi-jA-AET" secondAttribute="centerY" id="Uev-rc-gUg"/>
<constraint firstAttribute="trailingMargin" secondItem="D2X-9O-iQw" secondAttribute="trailing" id="cCQ-XZ-ojE"/>
<constraint firstItem="D2X-9O-iQw" firstAttribute="centerY" secondItem="KVi-jA-AET" secondAttribute="centerY" id="sdl-wt-H7w"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="contentLabel" destination="8eA-yd-rBp" id="Uy0-8G-WbU"/>
<outlet property="lastModifiedLabel" destination="D2X-9O-iQw" id="dx7-0E-RuM"/>
</connections>
<point key="canvasLocation" x="-388" y="141"/>
</tableViewCell>
</objects>
</document>

View File

@ -0,0 +1,69 @@
//
// DraftsTableViewController.swift
// Tusker
//
// Created by Shadowfacts on 10/22/18.
// Copyright © 2018 Shadowfacts. All rights reserved.
//
import UIKit
protocol DraftsTableViewControllerDelegate {
func draftSelectionCanceled()
func draftSelected(_ draft: DraftsManager.Draft)
}
class DraftsTableViewController: UITableViewController {
var delegate: DraftsTableViewControllerDelegate?
init() {
super.init(nibName: "DraftsTableViewController", bundle: nil)
title = "Drafts"
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelPressed))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "DraftTableViewCell", bundle: nil), forCellReuseIdentifier: "draftCell")
}
func draft(for indexPath: IndexPath) -> DraftsManager.Draft {
return DraftsManager.shared.sorted[indexPath.row]
}
// MARK: - Table View Data Source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return DraftsManager.shared.drafts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "draftCell", for: indexPath) as? DraftTableViewCell else { fatalError() }
cell.updateUI(for: draft(for: indexPath))
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.draftSelected(draft(for: indexPath))
dismiss(animated: true)
}
@objc func cancelPressed() {
delegate?.draftSelectionCanceled()
dismiss(animated: true)
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.23.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.16.1"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="DraftsTableViewController" customModule="Tusker" customModuleProvider="target">
<connections>
<outlet property="view" destination="O5v-ea-iTS" id="sft-3K-LZf"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="O5v-ea-iTS">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<point key="canvasLocation" x="-302" y="87"/>
</tableView>
</objects>
</document>

View File

@ -44,10 +44,10 @@
</tableViewCell> </tableViewCell>
</cells> </cells>
</tableViewSection> </tableViewSection>
<tableViewSection id="QnL-PI-wDE"> <tableViewSection headerTitle="Behavior" id="QnL-PI-wDE">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="RwH-Ti-TH8"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="RwH-Ti-TH8">
<rect key="frame" x="0.0" y="115" width="375" height="44"/> <rect key="frame" x="0.0" y="135" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="RwH-Ti-TH8" id="NJF-ED-5cF"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="RwH-Ti-TH8" id="NJF-ED-5cF">
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/> <rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
@ -77,12 +77,40 @@
<segue destination="50Z-Q7-qIn" kind="show" id="uHj-Vc-3uZ"/> <segue destination="50Z-Q7-qIn" kind="show" id="uHj-Vc-3uZ"/>
</connections> </connections>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="FPb-UJ-alk">
<rect key="frame" x="0.0" y="179" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="FPb-UJ-alk" id="vRj-wg-vTL">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Automatically Save Drafts" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lqn-WQ-Yef">
<rect key="frame" x="16" y="11.5" width="196" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Fei-jC-WaU">
<rect key="frame" x="310" y="6.5" width="51" height="31"/>
<connections>
<action selector="automaticallySaveDraftsChanged:" destination="ArB-e7-yko" eventType="valueChanged" id="cDM-q0-y3g"/>
</connections>
</switch>
</subviews>
<constraints>
<constraint firstItem="lqn-WQ-Yef" firstAttribute="centerY" secondItem="vRj-wg-vTL" secondAttribute="centerY" id="OfL-f9-0TD"/>
<constraint firstItem="lqn-WQ-Yef" firstAttribute="leading" secondItem="vRj-wg-vTL" secondAttribute="leadingMargin" id="PAD-91-xjs"/>
<constraint firstItem="Fei-jC-WaU" firstAttribute="centerY" secondItem="vRj-wg-vTL" secondAttribute="centerY" id="VuC-3Z-594"/>
<constraint firstAttribute="trailingMargin" secondItem="Fei-jC-WaU" secondAttribute="trailing" id="f0d-f8-rrC"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</cells> </cells>
</tableViewSection> </tableViewSection>
<tableViewSection id="5L1-9T-nha"> <tableViewSection id="5L1-9T-nha">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="eQh-JA-eyx"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="eQh-JA-eyx">
<rect key="frame" x="0.0" y="195" width="375" height="44"/> <rect key="frame" x="0.0" y="259" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="eQh-JA-eyx" id="2y5-gN-4xJ"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="eQh-JA-eyx" id="2y5-gN-4xJ">
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/> <rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
@ -114,6 +142,7 @@
</tableView> </tableView>
<navigationItem key="navigationItem" title="Preferences" id="dN7-yl-voz"/> <navigationItem key="navigationItem" title="Preferences" id="dN7-yl-voz"/>
<connections> <connections>
<outlet property="automaticallySaveDraftsSwitch" destination="Fei-jC-WaU" id="v9v-C2-JJp"/>
<outlet property="defaultPostVisibilityLabel" destination="se3-JR-wRN" id="YQM-H1-DBK"/> <outlet property="defaultPostVisibilityLabel" destination="se3-JR-wRN" id="YQM-H1-DBK"/>
</connections> </connections>
</tableViewController> </tableViewController>

View File

@ -17,6 +17,13 @@ class PreferencesTableViewController: UITableViewController {
@IBOutlet weak var defaultPostVisibilityLabel: UILabel! @IBOutlet weak var defaultPostVisibilityLabel: UILabel!
@IBOutlet weak var automaticallySaveDraftsSwitch: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
automaticallySaveDraftsSwitch.setOn(Preferences.shared.automaticallySaveDrafts, animated: false)
}
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
@ -24,14 +31,8 @@ class PreferencesTableViewController: UITableViewController {
defaultPostVisibilityLabel.text = Preferences.shared.defaultPostVisibility.displayName defaultPostVisibilityLabel.text = Preferences.shared.defaultPostVisibility.displayName
} }
/* @IBAction func automaticallySaveDraftsChanged(_ sender: Any) {
// MARK: - Navigation Preferences.shared.automaticallySaveDrafts = automaticallySaveDraftsSwitch.isOn
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
} }
*/
} }