forked from shadowfacts/Tusker
Fix various issues when dealing with multiple Compose/Drafts screens simultaneously
This commit is contained in:
parent
f004c82302
commit
d84d402271
|
@ -10,6 +10,7 @@ import Combine
|
|||
import Pachyderm
|
||||
import TuskerComponents
|
||||
import MatchedGeometryPresentation
|
||||
import CoreData
|
||||
|
||||
public final class ComposeController: ViewController {
|
||||
public typealias FetchAttachment = (URL) async -> UIImage?
|
||||
|
@ -54,6 +55,9 @@ public final class ComposeController: ViewController {
|
|||
@Published public private(set) var didPostSuccessfully = false
|
||||
@Published var hasChangedLanguageSelection = false
|
||||
|
||||
private var isDisappearing = false
|
||||
private var userConfirmedDelete = false
|
||||
|
||||
var isPosting: Bool {
|
||||
poster != nil
|
||||
}
|
||||
|
@ -119,6 +123,7 @@ public final class ComposeController: ViewController {
|
|||
if #available(iOS 16.0, *) {
|
||||
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 {
|
||||
|
@ -129,6 +134,15 @@ public final class ComposeController: ViewController {
|
|||
.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 {
|
||||
guard itemProviders.allSatisfy({ $0.canLoadObject(ofClass: DraftAttachment.self) }) else {
|
||||
return false
|
||||
|
@ -172,6 +186,7 @@ public final class ComposeController: ViewController {
|
|||
@MainActor
|
||||
func cancel(deleteDraft: Bool) {
|
||||
deleteDraftOnDisappear = true
|
||||
userConfirmedDelete = true
|
||||
config.dismiss(.cancel)
|
||||
}
|
||||
|
||||
|
@ -216,16 +231,18 @@ public final class ComposeController: ViewController {
|
|||
}
|
||||
|
||||
func selectDraft(_ newDraft: Draft) {
|
||||
if !self.draft.hasContent {
|
||||
DraftsPersistentContainer.shared.viewContext.delete(self.draft)
|
||||
let oldDraft = self.draft
|
||||
self.draft = newDraft
|
||||
|
||||
if !oldDraft.hasContent {
|
||||
DraftsPersistentContainer.shared.viewContext.delete(oldDraft)
|
||||
}
|
||||
DraftsPersistentContainer.shared.save()
|
||||
|
||||
self.draft = newDraft
|
||||
}
|
||||
|
||||
func onDisappear() {
|
||||
if deleteDraftOnDisappear && (!draft.hasContent || didPostSuccessfully) {
|
||||
isDisappearing = true
|
||||
if deleteDraftOnDisappear && (!draft.hasContent || didPostSuccessfully || userConfirmedDelete) {
|
||||
DraftsPersistentContainer.shared.viewContext.delete(draft)
|
||||
}
|
||||
DraftsPersistentContainer.shared.save()
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import SwiftUI
|
||||
import TuskerComponents
|
||||
import CoreData
|
||||
|
||||
class DraftsController: ViewController {
|
||||
|
||||
|
@ -152,12 +153,14 @@ private struct DraftRow: View {
|
|||
|
||||
Spacer()
|
||||
|
||||
Text(draft.lastModified.formatted(.abbreviatedTimeAgo))
|
||||
if let lastModified = draft.lastModified {
|
||||
Text(lastModified.formatted(.abbreviatedTimeAgo))
|
||||
.font(.body)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension View {
|
||||
@ViewBuilder
|
||||
|
|
|
@ -108,7 +108,7 @@ private struct DismissFocusedAttachmentButtonStyle: ButtonStyle {
|
|||
}
|
||||
|
||||
struct AttachmentDescriptionTextViewID: Hashable {
|
||||
let attachmentID: UUID
|
||||
let attachmentID: UUID!
|
||||
|
||||
init(_ attachment: DraftAttachment) {
|
||||
self.attachmentID = attachment.id
|
||||
|
|
|
@ -28,7 +28,7 @@ public class Draft: NSManagedObject, Identifiable {
|
|||
@NSManaged public var initialText: String
|
||||
@NSManaged public var inReplyToID: String?
|
||||
@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 text: String
|
||||
@NSManaged private var visibilityStr: String
|
||||
|
|
|
@ -26,7 +26,7 @@ public final class DraftAttachment: NSManagedObject, Identifiable {
|
|||
@NSManaged public var editedAttachmentURL: URL?
|
||||
@NSManaged public var fileURL: URL?
|
||||
@NSManaged internal var fileType: String?
|
||||
@NSManaged public var id: UUID
|
||||
@NSManaged public var id: UUID!
|
||||
|
||||
@NSManaged internal var draft: Draft
|
||||
|
||||
|
|
|
@ -18,10 +18,6 @@ struct PollOptionView: View {
|
|||
self.remove = remove
|
||||
}
|
||||
|
||||
private var optionIndex: Int {
|
||||
poll.options.index(of: option)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 4) {
|
||||
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 {
|
||||
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
|
||||
return EmojiTextField(text: $option.text, placeholder: placeholder, maxLength: maxLength)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue