forked from shadowfacts/Tusker
Add preference to require attachment descriptions before posting
Closes #76
This commit is contained in:
parent
8178a1f339
commit
23de131290
|
@ -73,6 +73,7 @@
|
|||
D61AC1D5232E9FA600C54D2D /* InstanceSelectorTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61AC1D4232E9FA600C54D2D /* InstanceSelectorTableViewController.swift */; };
|
||||
D61AC1D8232EA42D00C54D2D /* InstanceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61AC1D6232EA42D00C54D2D /* InstanceTableViewCell.swift */; };
|
||||
D61AC1D9232EA42D00C54D2D /* InstanceTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D61AC1D7232EA42D00C54D2D /* InstanceTableViewCell.xib */; };
|
||||
D620483223D2A6A3008A63EF /* CompositionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483123D2A6A3008A63EF /* CompositionState.swift */; };
|
||||
D626493323BD751600612E6E /* ShowCameraCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D626493123BD751600612E6E /* ShowCameraCollectionViewCell.xib */; };
|
||||
D626493523BD94CE00612E6E /* CompositionAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D626493423BD94CE00612E6E /* CompositionAttachment.swift */; };
|
||||
D626493823C0FD0000612E6E /* AllPhotosTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D626493623C0FD0000612E6E /* AllPhotosTableViewCell.swift */; };
|
||||
|
@ -344,6 +345,7 @@
|
|||
D61AC1D4232E9FA600C54D2D /* InstanceSelectorTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceSelectorTableViewController.swift; sourceTree = "<group>"; };
|
||||
D61AC1D6232EA42D00C54D2D /* InstanceTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceTableViewCell.swift; sourceTree = "<group>"; };
|
||||
D61AC1D7232EA42D00C54D2D /* InstanceTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InstanceTableViewCell.xib; sourceTree = "<group>"; };
|
||||
D620483123D2A6A3008A63EF /* CompositionState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionState.swift; sourceTree = "<group>"; };
|
||||
D626493123BD751600612E6E /* ShowCameraCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ShowCameraCollectionViewCell.xib; sourceTree = "<group>"; };
|
||||
D626493423BD94CE00612E6E /* CompositionAttachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionAttachment.swift; sourceTree = "<group>"; };
|
||||
D626493623C0FD0000612E6E /* AllPhotosTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllPhotosTableViewCell.swift; sourceTree = "<group>"; };
|
||||
|
|
|
@ -45,6 +45,7 @@ class Preferences: Codable, ObservableObject {
|
|||
self.defaultPostVisibility = try container.decode(Status.Visibility.self, forKey: .defaultPostVisibility)
|
||||
self.automaticallySaveDrafts = try container.decode(Bool.self, forKey: .automaticallySaveDrafts)
|
||||
self.contentWarningCopyMode = try container.decode(ContentWarningCopyMode.self, forKey: .contentWarningCopyMode)
|
||||
self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions)
|
||||
self.blurAllMedia = try container.decode(Bool.self, forKey: .blurAllMedia)
|
||||
self.openLinksInApps = try container.decode(Bool.self, forKey: .openLinksInApps)
|
||||
self.useInAppSafari = try container.decode(Bool.self, forKey: .useInAppSafari)
|
||||
|
@ -68,6 +69,7 @@ class Preferences: Codable, ObservableObject {
|
|||
try container.encode(defaultPostVisibility, forKey: .defaultPostVisibility)
|
||||
try container.encode(automaticallySaveDrafts, forKey: .automaticallySaveDrafts)
|
||||
try container.encode(contentWarningCopyMode, forKey: .contentWarningCopyMode)
|
||||
try container.encode(requireAttachmentDescriptions, forKey: .requireAttachmentDescriptions)
|
||||
try container.encode(blurAllMedia, forKey: .blurAllMedia)
|
||||
try container.encode(openLinksInApps, forKey: .openLinksInApps)
|
||||
try container.encode(useInAppSafari, forKey: .useInAppSafari)
|
||||
|
@ -90,6 +92,7 @@ class Preferences: Codable, ObservableObject {
|
|||
@Published var defaultPostVisibility = Status.Visibility.public
|
||||
@Published var automaticallySaveDrafts = true
|
||||
@Published var contentWarningCopyMode = ContentWarningCopyMode.asIs
|
||||
@Published var requireAttachmentDescriptions = false
|
||||
@Published var blurAllMedia = false
|
||||
@Published var openLinksInApps = true
|
||||
@Published var useInAppSafari = true
|
||||
|
@ -112,6 +115,7 @@ class Preferences: Codable, ObservableObject {
|
|||
case defaultPostVisibility
|
||||
case automaticallySaveDrafts
|
||||
case contentWarningCopyMode
|
||||
case requireAttachmentDescriptions
|
||||
case blurAllMedia
|
||||
case openLinksInApps
|
||||
case useInAppSafari
|
||||
|
|
|
@ -37,6 +37,12 @@ class ComposeViewController: UIViewController {
|
|||
weak var xcbSession: XCBSession?
|
||||
var postedStatus: Status?
|
||||
|
||||
var compositionState: CompositionState = .valid {
|
||||
didSet {
|
||||
postBarButtonItem.isEnabled = compositionState.isValid
|
||||
}
|
||||
}
|
||||
|
||||
weak var postBarButtonItem: UIBarButtonItem!
|
||||
var visibilityBarButtonItem: UIBarButtonItem!
|
||||
var contentWarningBarButtonItem: UIBarButtonItem!
|
||||
|
@ -131,6 +137,7 @@ class ComposeViewController: UIViewController {
|
|||
// 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()
|
||||
updateAttachmentDescriptionsRequired()
|
||||
updatePlaceholder()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(contentWarningTextFieldDidChange), name: UITextField.textDidChangeNotification, object: contentWarningTextField)
|
||||
|
@ -266,17 +273,29 @@ class ComposeViewController: UIViewController {
|
|||
scrollView.scrollIndicatorInsets = scrollView.contentInset
|
||||
}
|
||||
|
||||
func updateAttachmentDescriptionsRequired() {
|
||||
if Preferences.shared.requireAttachmentDescriptions {
|
||||
for case let mediaView as ComposeMediaView in attachmentsStackView.arrangedSubviews {
|
||||
if mediaView.descriptionTextView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
compositionState.formUnion(.requiresAttachmentDescriptions)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
compositionState.subtract(.requiresAttachmentDescriptions)
|
||||
}
|
||||
|
||||
func updateCharactersRemaining() {
|
||||
// TODO: include CW char count
|
||||
let count = CharacterCounter.count(text: statusTextView.text)
|
||||
let cwCount = contentWarningEnabled ? (contentWarningTextField.text?.count ?? 0) : 0
|
||||
let remaining = (MastodonController.instance.maxStatusCharacters ?? 500) - count - cwCount
|
||||
if remaining < 0 {
|
||||
charactersRemainingLabel.textColor = .red
|
||||
postBarButtonItem.isEnabled = false
|
||||
compositionState.formUnion(.tooManyCharacters)
|
||||
} else {
|
||||
charactersRemainingLabel.textColor = .darkGray
|
||||
postBarButtonItem.isEnabled = true
|
||||
compositionState.subtract(.tooManyCharacters)
|
||||
}
|
||||
charactersRemainingLabel.text = String(remaining)
|
||||
charactersRemainingLabel.accessibilityLabel = String(format: NSLocalizedString("%d characters remaining", comment: "compose characters remaining accessibility label"), remaining)
|
||||
|
@ -454,7 +473,7 @@ class ComposeViewController: UIViewController {
|
|||
saveDraft()
|
||||
|
||||
// disable post button while sending post request
|
||||
postBarButtonItem.isEnabled = false
|
||||
compositionState.formUnion(.currentlyPosting)
|
||||
|
||||
let contentWarning: String?
|
||||
if contentWarningEnabled, let cwText = contentWarningTextField.text, !cwText.isEmpty {
|
||||
|
@ -575,6 +594,7 @@ extension ComposeViewController: AssetPickerViewControllerDelegate {
|
|||
}
|
||||
func assetPicker(_ assetPicker: AssetPickerViewController, didSelectAttachments attachments: [CompositionAttachment]) {
|
||||
selectedAttachments.append(contentsOf: attachments)
|
||||
updateAttachmentDescriptionsRequired()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -583,6 +603,11 @@ extension ComposeViewController: ComposeMediaViewDelegate {
|
|||
let index = attachmentsStackView.arrangedSubviews.firstIndex(of: mediaView)!
|
||||
selectedAttachments.remove(at: index)
|
||||
updateAddAttachmentButton()
|
||||
updateAttachmentDescriptionsRequired()
|
||||
}
|
||||
|
||||
func descriptionTextViewDidChange(_ mediaView: ComposeMediaView) {
|
||||
updateAttachmentDescriptionsRequired()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -620,7 +645,7 @@ extension ComposeViewController: DraftsTableViewControllerDelegate {
|
|||
|
||||
updatePlaceholder()
|
||||
updateCharactersRemaining()
|
||||
|
||||
|
||||
selectedAttachments = draft.attachments.map { $0.attachment }
|
||||
updateAttachmentViews()
|
||||
|
||||
|
@ -631,6 +656,8 @@ extension ComposeViewController: DraftsTableViewControllerDelegate {
|
|||
// call the delegate method manually, since setting the text property doesn't call it
|
||||
mediaView.textViewDidChange(mediaView.descriptionTextView)
|
||||
}
|
||||
|
||||
updateAttachmentDescriptionsRequired()
|
||||
}
|
||||
|
||||
func draftSelectionCompleted() {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// CompositionState.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 1/17/20.
|
||||
// Copyright © 2020 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct CompositionState: OptionSet {
|
||||
let rawValue: Int
|
||||
|
||||
static let currentlyPosting = CompositionState(rawValue: 1 << 0)
|
||||
static let tooManyCharacters = CompositionState(rawValue: 1 << 1)
|
||||
static let requiresAttachmentDescriptions = CompositionState(rawValue: 1 << 2)
|
||||
|
||||
static let valid: CompositionState = []
|
||||
|
||||
var isValid: Bool {
|
||||
isEmpty
|
||||
}
|
||||
}
|
|
@ -40,6 +40,9 @@ struct BehaviorPrefsView: View {
|
|||
Text("Prepend 're: '").tag(ContentWarningCopyMode.prependRe)
|
||||
Text("Don't copy").tag(ContentWarningCopyMode.doNotCopy)
|
||||
}
|
||||
Toggle(isOn: $preferences.requireAttachmentDescriptions) {
|
||||
Text("Require Attachment Descriptions")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import AVFoundation
|
|||
|
||||
protocol ComposeMediaViewDelegate {
|
||||
func didRemoveMedia(_ mediaView: ComposeMediaView)
|
||||
func descriptionTextViewDidChange(_ mediaView: ComposeMediaView)
|
||||
}
|
||||
|
||||
class ComposeMediaView: UIView {
|
||||
|
@ -69,5 +70,6 @@ class ComposeMediaView: UIView {
|
|||
extension ComposeMediaView: UITextViewDelegate {
|
||||
func textViewDidChange(_ textView: UITextView) {
|
||||
placeholderLabel.isHidden = !descriptionTextView.text.isEmpty
|
||||
delegate?.descriptionTextViewDidChange(self)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue