Compare commits

...

5 Commits

11 changed files with 49 additions and 39 deletions

View File

@ -26,7 +26,6 @@ public struct ComposeUIConfig {
// Preferences
public var useTwitterKeyboard = false
public var contentType = StatusContentType.plain
public var automaticallySaveDrafts = false
public var requireAttachmentDescriptions = false
// Host callbacks

View File

@ -16,14 +16,13 @@ class AttachmentThumbnailController: ViewController {
@Published private var image: UIImage?
@Published private var gifController: GIFController?
@Published private var fullSize: Bool = false
@Published private var imageBackground: Color?
init(attachment: DraftAttachment) {
self.attachment = attachment
}
func loadImageIfNecessary(fullSize: Bool) {
if (gifController != nil) || (image != nil && fullSize == self.fullSize) {
if (gifController != nil) || (image != nil && self.fullSize) {
return
}
self.fullSize = fullSize

View File

@ -148,15 +148,11 @@ public final class ComposeController: ViewController {
@MainActor
func cancel() {
if config.automaticallySaveDrafts {
config.dismiss(.cancel)
if draft.hasContent {
isShowingSaveDraftSheet = true
} else {
if draft.hasContent {
isShowingSaveDraftSheet = true
} else {
deleteDraftOnDisappear = true
config.dismiss(.cancel)
}
deleteDraftOnDisappear = true
config.dismiss(.cancel)
}
}

View File

@ -10,7 +10,7 @@ import UIKit
public protocol DuckableViewController: UIViewController {
var duckableDelegate: DuckableViewControllerDelegate? { get set }
func duckableViewControllerShouldDuck() -> Bool
func duckableViewControllerShouldDuck() -> DuckAttemptAction
func duckableViewControllerMayAttemptToDuck()
@ -20,7 +20,7 @@ public protocol DuckableViewController: UIViewController {
}
extension DuckableViewController {
public func duckableViewControllerShouldDuck() -> Bool { true }
public func duckableViewControllerShouldDuck() -> DuckAttemptAction { .duck }
public func duckableViewControllerMayAttemptToDuck() {}
public func duckableViewControllerWillAnimateDuck(withDuration duration: CGFloat, afterDelay delay: CGFloat) {}
public func duckableViewControllerDidFinishAnimatingDuck() {}
@ -30,6 +30,12 @@ public protocol DuckableViewControllerDelegate: AnyObject {
func duckableViewControllerWillDismiss(animated: Bool)
}
public enum DuckAttemptAction {
case duck
case dismiss
case block
}
extension UIViewController {
@available(iOS 16.0, *)
public func presentDuckable(_ viewController: DuckableViewController, animated: Bool, isDucked: Bool = false) -> Bool {

View File

@ -135,14 +135,18 @@ public class DuckableContainerViewController: UIViewController, DuckableViewCont
guard case .presentingDucked(let viewController, isFirstPresentation: _) = state else {
return
}
guard viewController.duckableViewControllerShouldDuck() else {
switch viewController.duckableViewControllerShouldDuck() {
case .duck:
let placeholder = createPlaceholderForDuckedViewController(viewController)
state = .ducked(viewController, placeholder: placeholder)
configureChildForDuckedPlaceholder()
dismiss(animated: true)
case .block:
viewController.sheetPresentationController!.selectedDetentIdentifier = .large
return
case .dismiss:
duckableViewControllerWillDismiss(animated: true)
dismiss(animated: true)
}
let placeholder = createPlaceholderForDuckedViewController(viewController)
state = .ducked(viewController, placeholder: placeholder)
configureChildForDuckedPlaceholder()
dismiss(animated: true)
}
private func configureChildForDuckedPlaceholder() {

View File

@ -110,18 +110,20 @@ class MatchedGeometryViewController<Content: View>: UIViewController, UIViewCont
}
}
@ViewBuilder
func matchedView(id: AnyHashable, source: () -> AnyView) -> some View {
let frame = state.currentFrames[id]!
let dest = state.destinations[id]!.0
return ZStack {
source()
dest
.opacity(state.mode == .presenting ? (state.animating ? 1 : 0) : (state.animating ? 0 : 1))
if let frame = state.currentFrames[id],
let dest = state.destinations[id]?.0 {
ZStack {
source()
dest
.opacity(state.mode == .presenting ? (state.animating ? 1 : 0) : (state.animating ? 0 : 1))
}
.frame(width: frame.width, height: frame.height)
.position(x: frame.midX, y: frame.midY)
.ignoresSafeArea()
.animation(.interpolatingSpring(mass: Double(mass), stiffness: Double(state.mode == .presenting ? presentStiffness : dismissStiffness), damping: Double(state.mode == .presenting ? presentDamping : dismissDamping), initialVelocity: 0), value: frame)
}
.frame(width: frame.width, height: frame.height)
.position(x: frame.midX, y: frame.midY)
.ignoresSafeArea()
.animation(.interpolatingSpring(mass: Double(mass), stiffness: Double(state.mode == .presenting ? presentStiffness : dismissStiffness), damping: Double(state.mode == .presenting ? presentDamping : dismissDamping), initialVelocity: 0), value: frame)
}
}
@ -150,6 +152,8 @@ class MatchedGeometryPresentationAnimationController<Content: View>: NSObject, U
let container = transitionContext.containerView
// add the VC to the container, which kicks off layout out the content hosting controller
matchedGeomVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
matchedGeomVC.view.frame = container.bounds
container.addSubview(matchedGeomVC.view)
// layout out the content hosting controller and having enough destinations may take a while

View File

@ -63,7 +63,6 @@ public class Preferences: Codable, ObservableObject {
self.defaultPostVisibility = try container.decode(Visibility.self, forKey: .defaultPostVisibility)
self.defaultReplyVisibility = try container.decodeIfPresent(ReplyVisibility.self, forKey: .defaultReplyVisibility) ?? .sameAsPost
self.automaticallySaveDrafts = try container.decode(Bool.self, forKey: .automaticallySaveDrafts)
self.requireAttachmentDescriptions = try container.decode(Bool.self, forKey: .requireAttachmentDescriptions)
self.contentWarningCopyMode = try container.decode(ContentWarningCopyMode.self, forKey: .contentWarningCopyMode)
self.mentionReblogger = try container.decode(Bool.self, forKey: .mentionReblogger)
@ -120,7 +119,6 @@ public class Preferences: Codable, ObservableObject {
try container.encode(defaultPostVisibility, forKey: .defaultPostVisibility)
try container.encode(defaultReplyVisibility, forKey: .defaultReplyVisibility)
try container.encode(automaticallySaveDrafts, forKey: .automaticallySaveDrafts)
try container.encode(requireAttachmentDescriptions, forKey: .requireAttachmentDescriptions)
try container.encode(contentWarningCopyMode, forKey: .contentWarningCopyMode)
try container.encode(mentionReblogger, forKey: .mentionReblogger)
@ -172,7 +170,6 @@ public class Preferences: Codable, ObservableObject {
// MARK: Composing
@Published public var defaultPostVisibility = Visibility.public
@Published public var defaultReplyVisibility = ReplyVisibility.sameAsPost
@Published public var automaticallySaveDrafts = true
@Published public var requireAttachmentDescriptions = false
@Published public var contentWarningCopyMode = ContentWarningCopyMode.asIs
@Published public var mentionReblogger = false
@ -236,7 +233,6 @@ public class Preferences: Codable, ObservableObject {
case defaultPostVisibility
case defaultReplyVisibility
case automaticallySaveDrafts
case requireAttachmentDescriptions
case contentWarningCopyMode
case mentionReblogger

View File

@ -74,8 +74,6 @@ class ShareHostingController: UIHostingController<ShareHostingController.View> {
var config = ComposeUIConfig()
config.allowSwitchingDrafts = false
config.textSelectionStartsAtBeginning = true
// note: in the share sheet, we ignore this preference
config.automaticallySaveDrafts = false
config.backgroundColor = Color(uiColor: .appBackground)
config.groupedBackgroundColor = Color(uiColor: .appGroupedBackground)

View File

@ -60,6 +60,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
}
// make sure the persistent container is initialized on the main thread
// otherwise initializing it on the background thread can deadlock with accessing it on the main thread elsewhere
_ = DraftsPersistentContainer.shared
DispatchQueue.global(qos: .userInitiated).async {
let oldDraftsFile = documentsDirectory.appendingPathComponent("drafts").appendingPathExtension("plist")
let appGroupDraftsFile = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.space.vaccor.Tusker")!.appendingPathComponent("drafts").appendingPathExtension("plist")

View File

@ -79,7 +79,6 @@ class ComposeHostingController: UIHostingController<ComposeHostingController.Vie
config.useTwitterKeyboard = Preferences.shared.useTwitterKeyboard
config.contentType = Preferences.shared.statusContentType
config.automaticallySaveDrafts = Preferences.shared.automaticallySaveDrafts
config.requireAttachmentDescriptions = Preferences.shared.requireAttachmentDescriptions
config.dismiss = { [unowned self] in self.dismiss(mode: $0) }
@ -138,6 +137,14 @@ class ComposeHostingController: UIHostingController<ComposeHostingController.Vie
// MARK: Duckable
func duckableViewControllerShouldDuck() -> DuckAttemptAction {
if controller.draft.hasContent {
return .duck
} else {
return .dismiss
}
}
func duckableViewControllerWillAnimateDuck(withDuration duration: CGFloat, afterDelay delay: CGFloat) {
controller.deleteDraftOnDisappear = false

View File

@ -58,9 +58,6 @@ struct ComposingPrefsView: View {
var composingSection: some View {
Section(header: Text("Composing")) {
Toggle(isOn: $preferences.automaticallySaveDrafts) {
Text("Automatically Save Drafts")
}
Toggle(isOn: $preferences.requireAttachmentDescriptions) {
Text("Require Attachment Descriptions")
}