Fix various issues when dealing with multiple Compose/Drafts screens simultaneously

This commit is contained in:
Shadowfacts 2023-05-15 22:57:07 -04:00
parent f004c82302
commit d84d402271
6 changed files with 33 additions and 16 deletions

View File

@ -10,6 +10,7 @@ import Combine
import Pachyderm import Pachyderm
import TuskerComponents import TuskerComponents
import MatchedGeometryPresentation import MatchedGeometryPresentation
import CoreData
public final class ComposeController: ViewController { public final class ComposeController: ViewController {
public typealias FetchAttachment = (URL) async -> UIImage? public typealias FetchAttachment = (URL) async -> UIImage?
@ -54,6 +55,9 @@ public final class ComposeController: ViewController {
@Published public private(set) var didPostSuccessfully = false @Published public private(set) var didPostSuccessfully = false
@Published var hasChangedLanguageSelection = false @Published var hasChangedLanguageSelection = false
private var isDisappearing = false
private var userConfirmedDelete = false
var isPosting: Bool { var isPosting: Bool {
poster != nil poster != nil
} }
@ -119,6 +123,7 @@ public final class ComposeController: ViewController {
if #available(iOS 16.0, *) { if #available(iOS 16.0, *) {
NotificationCenter.default.addObserver(self, selector: #selector(currentInputModeChanged), name: UITextInputMode.currentInputModeDidChangeNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(currentInputModeChanged), name: UITextInputMode.currentInputModeDidChangeNotification, object: nil)
} }
NotificationCenter.default.addObserver(self, selector: #selector(managedObjectsDidChange), name: .NSManagedObjectContextObjectsDidChange, object: DraftsPersistentContainer.shared.viewContext)
} }
public var view: some View { public var view: some View {
@ -129,6 +134,15 @@ public final class ComposeController: ViewController {
.environment(\.composeUIConfig, config) .environment(\.composeUIConfig, config)
} }
@MainActor
@objc private func managedObjectsDidChange(_ notification: Foundation.Notification) {
if let deleted = notification.userInfo?[NSDeletedObjectsKey] as? Set<NSManagedObject>,
deleted.contains(where: { $0.objectID == self.draft.objectID }),
!isDisappearing {
self.config.dismiss(.cancel)
}
}
public func canPaste(itemProviders: [NSItemProvider]) -> Bool { public func canPaste(itemProviders: [NSItemProvider]) -> Bool {
guard itemProviders.allSatisfy({ $0.canLoadObject(ofClass: DraftAttachment.self) }) else { guard itemProviders.allSatisfy({ $0.canLoadObject(ofClass: DraftAttachment.self) }) else {
return false return false
@ -172,6 +186,7 @@ public final class ComposeController: ViewController {
@MainActor @MainActor
func cancel(deleteDraft: Bool) { func cancel(deleteDraft: Bool) {
deleteDraftOnDisappear = true deleteDraftOnDisappear = true
userConfirmedDelete = true
config.dismiss(.cancel) config.dismiss(.cancel)
} }
@ -216,16 +231,18 @@ public final class ComposeController: ViewController {
} }
func selectDraft(_ newDraft: Draft) { func selectDraft(_ newDraft: Draft) {
if !self.draft.hasContent { let oldDraft = self.draft
DraftsPersistentContainer.shared.viewContext.delete(self.draft) self.draft = newDraft
if !oldDraft.hasContent {
DraftsPersistentContainer.shared.viewContext.delete(oldDraft)
} }
DraftsPersistentContainer.shared.save() DraftsPersistentContainer.shared.save()
self.draft = newDraft
} }
func onDisappear() { func onDisappear() {
if deleteDraftOnDisappear && (!draft.hasContent || didPostSuccessfully) { isDisappearing = true
if deleteDraftOnDisappear && (!draft.hasContent || didPostSuccessfully || userConfirmedDelete) {
DraftsPersistentContainer.shared.viewContext.delete(draft) DraftsPersistentContainer.shared.viewContext.delete(draft)
} }
DraftsPersistentContainer.shared.save() DraftsPersistentContainer.shared.save()

View File

@ -7,6 +7,7 @@
import SwiftUI import SwiftUI
import TuskerComponents import TuskerComponents
import CoreData
class DraftsController: ViewController { class DraftsController: ViewController {
@ -152,11 +153,13 @@ private struct DraftRow: View {
Spacer() Spacer()
Text(draft.lastModified.formatted(.abbreviatedTimeAgo)) if let lastModified = draft.lastModified {
Text(lastModified.formatted(.abbreviatedTimeAgo))
.font(.body) .font(.body)
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }
} }
}
} }
private extension View { private extension View {

View File

@ -108,7 +108,7 @@ private struct DismissFocusedAttachmentButtonStyle: ButtonStyle {
} }
struct AttachmentDescriptionTextViewID: Hashable { struct AttachmentDescriptionTextViewID: Hashable {
let attachmentID: UUID let attachmentID: UUID!
init(_ attachment: DraftAttachment) { init(_ attachment: DraftAttachment) {
self.attachmentID = attachment.id self.attachmentID = attachment.id

View File

@ -28,7 +28,7 @@ public class Draft: NSManagedObject, Identifiable {
@NSManaged public var initialText: String @NSManaged public var initialText: String
@NSManaged public var inReplyToID: String? @NSManaged public var inReplyToID: String?
@NSManaged public var language: String? // ISO 639 language code @NSManaged public var language: String? // ISO 639 language code
@NSManaged public var lastModified: Date @NSManaged public var lastModified: Date!
@NSManaged public var localOnly: Bool @NSManaged public var localOnly: Bool
@NSManaged public var text: String @NSManaged public var text: String
@NSManaged private var visibilityStr: String @NSManaged private var visibilityStr: String

View File

@ -26,7 +26,7 @@ public final class DraftAttachment: NSManagedObject, Identifiable {
@NSManaged public var editedAttachmentURL: URL? @NSManaged public var editedAttachmentURL: URL?
@NSManaged public var fileURL: URL? @NSManaged public var fileURL: URL?
@NSManaged internal var fileType: String? @NSManaged internal var fileType: String?
@NSManaged public var id: UUID @NSManaged public var id: UUID!
@NSManaged internal var draft: Draft @NSManaged internal var draft: Draft

View File

@ -18,10 +18,6 @@ struct PollOptionView: View {
self.remove = remove self.remove = remove
} }
private var optionIndex: Int {
poll.options.index(of: option)
}
var body: some View { var body: some View {
HStack(spacing: 4) { HStack(spacing: 4) {
Checkbox(radiusFraction: poll.multiple ? 0.1 : 0.5, background: controller.parent.config.backgroundColor) Checkbox(radiusFraction: poll.multiple ? 0.1 : 0.5, background: controller.parent.config.backgroundColor)
@ -41,7 +37,8 @@ struct PollOptionView: View {
} }
private var textField: some View { private var textField: some View {
let placeholder = "Option \(optionIndex + 1)" let index = poll.options.index(of: option)
let placeholder = index != NSNotFound ? "Option \(index + 1)" : ""
let maxLength = controller.parent.mastodonController.instanceFeatures.maxPollOptionChars let maxLength = controller.parent.mastodonController.instanceFeatures.maxPollOptionChars
return EmojiTextField(text: $option.text, placeholder: placeholder, maxLength: maxLength) return EmojiTextField(text: $option.text, placeholder: placeholder, maxLength: maxLength)
} }