diff --git a/iOS/Inspector/Inspector.storyboard b/iOS/Inspector/Inspector.storyboard index e05bb02b6..f1c6f47e0 100644 --- a/iOS/Inspector/Inspector.storyboard +++ b/iOS/Inspector/Inspector.storyboard @@ -1,9 +1,8 @@ - + - - + @@ -182,10 +181,10 @@ - + - + @@ -402,9 +401,6 @@ - - - diff --git a/iOS/Settings/ArticleThemesTableViewController.swift b/iOS/Settings/ArticleThemesTableViewController.swift index b7793d5c4..51f738cfa 100644 --- a/iOS/Settings/ArticleThemesTableViewController.swift +++ b/iOS/Settings/ArticleThemesTableViewController.swift @@ -7,8 +7,12 @@ // import Foundation - import UIKit +import UniformTypeIdentifiers + +extension UTType { + static var netNewsWireTheme: UTType { UTType(importedAs: "com.ranchero.netnewswire.theme") } +} class ArticleThemesTableViewController: UITableViewController { @@ -27,10 +31,10 @@ class ArticleThemesTableViewController: UITableViewController { } @objc func importTheme(_ sender: Any?) { - let docPicker = UIDocumentPickerViewController(documentTypes: ["com.ranchero.netnewswire.theme"], in: .import) - docPicker.delegate = self - docPicker.modalPresentationStyle = .formSheet - self.present(docPicker, animated: true) + let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.netNewsWireTheme]) + documentPicker.delegate = self + documentPicker.modalPresentationStyle = .formSheet + self.present(documentPicker, animated: true) } // MARK: - Table view data source @@ -119,5 +123,4 @@ extension ArticleThemesTableViewController: UIDocumentPickerDelegate { NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error": error]) } } - } diff --git a/iOS/Settings/SettingsViewController.swift b/iOS/Settings/SettingsViewController.swift index d54b5fe97..b40381773 100644 --- a/iOS/Settings/SettingsViewController.swift +++ b/iOS/Settings/SettingsViewController.swift @@ -470,9 +470,9 @@ private extension SettingsViewController { self.presentError(title: "OPML Export Error", message: error.localizedDescription) } - let docPicker = UIDocumentPickerViewController(url: tempFile, in: .exportToService) - docPicker.modalPresentationStyle = .formSheet - self.present(docPicker, animated: true) + let documentPicker = UIDocumentPickerViewController(forExporting: [tempFile]) + documentPicker.modalPresentationStyle = .formSheet + self.present(documentPicker, animated: true) } func openURL(_ urlString: String) { diff --git a/iOS/ShareExtension/ShareViewController.swift b/iOS/ShareExtension/ShareViewController.swift index 9da5495db..e81d2772e 100644 --- a/iOS/ShareExtension/ShareViewController.swift +++ b/iOS/ShareExtension/ShareViewController.swift @@ -12,6 +12,7 @@ import Account import Social import RSCore import RSTree +import UniformTypeIdentifiers class ShareViewController: SLComposeServiceViewController, ShareFolderPickerControllerDelegate { @@ -46,14 +47,14 @@ class ShareViewController: SLComposeServiceViewController, ShareFolderPickerCont // Try to get any HTML that is maybe passed in for item in self.extensionContext!.inputItems as! [NSExtensionItem] { for itemProvider in item.attachments! { - if itemProvider.hasItemConformingToTypeIdentifier(kUTTypePropertyList as String) { + if itemProvider.hasItemConformingToTypeIdentifier(UTType.propertyList.identifier) { provider = itemProvider } } } if provider != nil { - provider!.loadItem(forTypeIdentifier: kUTTypePropertyList as String, options: nil, completionHandler: { [weak self] (pList, error) in + provider!.loadItem(forTypeIdentifier: UTType.propertyList.identifier, options: nil, completionHandler: { [weak self] (pList, error) in if error != nil { return } @@ -73,14 +74,14 @@ class ShareViewController: SLComposeServiceViewController, ShareFolderPickerCont // Try to get the URL if it is passed in for item in self.extensionContext!.inputItems as! [NSExtensionItem] { for itemProvider in item.attachments! { - if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) { + if itemProvider.hasItemConformingToTypeIdentifier(UTType.url.identifier) { provider = itemProvider } } } if provider != nil { - provider!.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil, completionHandler: { [weak self] (urlCoded, error) in + provider!.loadItem(forTypeIdentifier: UTType.url.identifier, options: nil, completionHandler: { [weak self] (urlCoded, error) in if error != nil { return } diff --git a/iOS/UIKit Extensions/InteractiveLabel.swift b/iOS/UIKit Extensions/InteractiveLabel.swift index 89ae25d1c..12d12f105 100644 --- a/iOS/UIKit Extensions/InteractiveLabel.swift +++ b/iOS/UIKit Extensions/InteractiveLabel.swift @@ -9,7 +9,7 @@ import UIKit @IBDesignable -class InteractiveLabel: UILabel { +class InteractiveLabel: UILabel, UIEditMenuInteractionDelegate { override init(frame: CGRect) { super.init(frame: frame) @@ -24,18 +24,23 @@ class InteractiveLabel: UILabel { func commonInit() { let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(_:))) self.addGestureRecognizer(gestureRecognizer) + + let editMenuInteraction = UIEditMenuInteraction(delegate: self) + addInteraction(editMenuInteraction) + self.isUserInteractionEnabled = true } - + @objc func handleLongPressGesture(_ recognizer: UIGestureRecognizer) { - guard recognizer.state == .began, - let recognizerView = recognizer.view, - let recognizerSuperView = recognizerView.superview, - recognizerView.becomeFirstResponder() else { - return + guard recognizer.state == .began, let recognizerView = recognizer.view else { + return + } + + if let interaction = recognizerView.interactions.first(where: { $0 is UIEditMenuInteraction }) as? UIEditMenuInteraction { + let location = recognizer.location(in: recognizerView) + let editMenuConfiguration = UIEditMenuConfiguration(identifier: nil, sourcePoint: location) + interaction.presentEditMenu(with: editMenuConfiguration) } - - UIMenuController.shared.showMenu(from: recognizerSuperView, rect: recognizerView.frame) } override var canBecomeFirstResponder: Bool { @@ -44,11 +49,19 @@ class InteractiveLabel: UILabel { override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { return (action == #selector(UIResponderStandardEditActions.copy(_:))) - } override func copy(_ sender: Any?) { UIPasteboard.general.string = text } - + + // MARK: - UIEditMenuInteractionDelegate + + func editMenuInteraction(_ interaction: UIEditMenuInteraction, menuFor configuration: UIEditMenuConfiguration, suggestedActions: [UIMenuElement]) -> UIMenu? { + + let copyAction = UIAction(title: "Copy", image: nil) { [weak self] action in + self?.copy(nil) + } + return UIMenu(title: "", children: [copyAction]) + } }