diff --git a/Tusker/Screens/Compose/ComposeViewController.swift b/Tusker/Screens/Compose/ComposeViewController.swift index 3a48682b..49aadcbe 100644 --- a/Tusker/Screens/Compose/ComposeViewController.swift +++ b/Tusker/Screens/Compose/ComposeViewController.swift @@ -34,6 +34,7 @@ class ComposeViewController: UIViewController { } } + var hasChanges = false var currentDraft: 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 var xcbSession: XCBSession? @@ -83,7 +84,7 @@ class ComposeViewController: UIViewController { title = "Compose" tabBarItem.image = UIImage(systemName: "pencil") - navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelButtonPressed)) + navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(showSaveAndClosePrompt)) navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Post", style: .done, target: self, action: #selector(postButtonPressed)) postBarButtonItem = navigationItem.rightBarButtonItem } @@ -235,6 +236,14 @@ class ComposeViewController: UIViewController { charactersRemainingLabel.text = remaining.description } + func updateHasChanges() { + if let currentDraft = currentDraft { + hasChanges = statusTextView.text != currentDraft.text + } else { + hasChanges = !statusTextView.text.isEmpty + } + } + func updatePlaceholder() { placeholderLabel.isHidden = !statusTextView.text.isEmpty } @@ -304,7 +313,7 @@ class ComposeViewController: UIViewController { // MARK: - Interaction - @objc func cancelButtonPressed() { + @objc func showSaveAndClosePrompt() { guard statusTextView.text.trimmingCharacters(in: .whitespacesAndNewlines) != initialText else { close() return @@ -337,6 +346,7 @@ class ComposeViewController: UIViewController { @objc func contentWarningTextFieldDidChange() { updateCharactersRemaining() + updateHasChanges() } @objc func visbilityButtonPressed() { @@ -500,6 +510,7 @@ extension ComposeViewController: UITextViewDelegate { func textViewDidChange(_ textView: UITextView) { updateCharactersRemaining() updatePlaceholder() + updateHasChanges() } } @@ -552,3 +563,24 @@ extension ComposeViewController: DraftsTableViewControllerDelegate { } } } + +extension ComposeViewController: UIAdaptivePresentationControllerDelegate { + func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { + return Preferences.shared.automaticallySaveDrafts || !hasChanges + } + + func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) { + showSaveAndClosePrompt() + } + + // when the compose screen is dismissed interactively, close() isn't called, so we make sure to + // complete the X-Callback-URL session and save the draft is automatic saving is enabled + // (if automatic saving is off, the draft will get saved/discarded by the user when didAttemptToDismiss is called + func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { + if Preferences.shared.automaticallySaveDrafts { + saveDraft() + } + xcbSession?.complete(with: .cancel) + } +} + diff --git a/Tusker/Screens/Main/MainTabBarViewController.swift b/Tusker/Screens/Main/MainTabBarViewController.swift index 6bb6bf15..0c02f864 100644 --- a/Tusker/Screens/Main/MainTabBarViewController.swift +++ b/Tusker/Screens/Main/MainTabBarViewController.swift @@ -34,8 +34,10 @@ class MainTabBarViewController: UITabBarController, UITabBarControllerDelegate { func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool { if viewController is ComposeViewController { - let compose = embedInNavigationController(ComposeViewController()) - tabBarController.present(compose, animated: true) + let compose = ComposeViewController() + let navigationController = embedInNavigationController(compose) + navigationController.presentationController?.delegate = compose + present(navigationController, animated: true) return false } return true