Add Live Text support to MediaPreviewImageView

This commit is contained in:
Jed Fox 2022-11-14 20:44:47 -05:00
parent 35f6732ad9
commit ac28c2ee4f
No known key found for this signature in database
GPG Key ID: 0B61D18EA54B47E1
3 changed files with 94 additions and 6 deletions

View File

@ -9,6 +9,7 @@ import os.log
import func AVFoundation.AVMakeRect
import UIKit
import FLAnimatedImage
import VisionKit
final class MediaPreviewImageView: UIScrollView {
@ -28,9 +29,21 @@ final class MediaPreviewImageView: UIScrollView {
tapGestureRecognizer.numberOfTapsRequired = 2
return tapGestureRecognizer
}()
private var containerFrame: CGRect?
private var _interaction: UIInteraction? = {
if #available(iOS 16.0, *) {
return ImageAnalysisInteraction()
} else {
return nil
}
}()
@available(iOS 16.0, *)
var liveTextInteraction: ImageAnalysisInteraction {
_interaction as! ImageAnalysisInteraction
}
override init(frame: CGRect) {
super.init(frame: frame)
_init()
@ -55,10 +68,14 @@ extension MediaPreviewImageView {
maximumZoomScale = 4.0
addSubview(imageView)
doubleTapGestureRecognizer.addTarget(self, action: #selector(MediaPreviewImageView.doubleTapGestureRecognizerHandler(_:)))
imageView.addGestureRecognizer(doubleTapGestureRecognizer)
if #available(iOS 16.0, *) {
liveTextInteraction.isSupplementaryInterfaceHidden = true
imageView.addInteraction(liveTextInteraction)
}
delegate = self
}
@ -129,6 +146,26 @@ extension MediaPreviewImageView {
centerScrollViewContents()
contentOffset = CGPoint(x: -contentInset.left, y: -contentInset.top)
if #available(iOS 16.0, *) {
Task.detached(priority: .userInitiated) {
do {
let analysis = try await ImageAnalyzer.shared.analyze(image, configuration: ImageAnalyzer.Configuration([.text, .machineReadableCode]))
await MainActor.run {
self.liveTextInteraction.analysis = analysis
self.liveTextInteraction.preferredInteractionTypes = .automatic
if self.liveTextInteraction.isSupplementaryInterfaceHidden {
self.liveTextInteraction.setSupplementaryInterfaceHidden(false, animated: true)
}
}
} catch {
await MainActor.run {
self.liveTextInteraction.preferredInteractionTypes = []
}
}
}
}
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: setup image for container %s", ((#file as NSString).lastPathComponent), #line, #function, container.frame.debugDescription)
}

View File

@ -11,6 +11,7 @@ import Combine
import MastodonAsset
import MastodonLocalization
import FLAnimatedImage
import VisionKit
protocol MediaPreviewImageViewControllerDelegate: AnyObject {
func mediaPreviewImageViewController(_ viewController: MediaPreviewImageViewController, tapGestureRecognizerDidTrigger tapGestureRecognizer: UITapGestureRecognizer)
@ -31,7 +32,7 @@ final class MediaPreviewImageViewController: UIViewController {
let tapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
let longPressGestureRecognizer = UILongPressGestureRecognizer()
deinit {
os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
previewImageView.imageView.af.cancelImageRequest()
@ -42,7 +43,10 @@ extension MediaPreviewImageViewController {
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 16.0, *) {
previewImageView.liveTextInteraction.delegate = self
}
previewImageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(previewImageView)
NSLayoutConstraint.activate([
@ -53,7 +57,9 @@ extension MediaPreviewImageViewController {
])
tapGestureRecognizer.addTarget(self, action: #selector(MediaPreviewImageViewController.tapGestureRecognizerHandler(_:)))
tapGestureRecognizer.delegate = self
longPressGestureRecognizer.addTarget(self, action: #selector(MediaPreviewImageViewController.longPressGestureRecognizerHandler(_:)))
longPressGestureRecognizer.delegate = self
tapGestureRecognizer.require(toFail: previewImageView.doubleTapGestureRecognizer)
tapGestureRecognizer.require(toFail: longPressGestureRecognizer)
previewImageView.addGestureRecognizer(tapGestureRecognizer)
@ -105,10 +111,42 @@ extension MediaPreviewImageViewController {
}
// MARK: - ImageAnalysisInteractionDelegate
@available(iOS 16.0, *)
extension MediaPreviewImageViewController: ImageAnalysisInteractionDelegate {
func contentView(for interaction: ImageAnalysisInteraction) -> UIView? {
view
}
func presentingViewController(for interaction: ImageAnalysisInteraction) -> UIViewController? {
self
}
}
// MARK: - UIGestureRecognizerDelegate
extension MediaPreviewImageViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if #available(iOS 16.0, *) {
let location = touch.location(in: previewImageView.imageView)
let hasItem = previewImageView.liveTextInteraction.hasInteractiveItem(at: location)
return !hasItem
} else {
return true
}
}
}
// MARK: - UIContextMenuInteractionDelegate
extension MediaPreviewImageViewController: UIContextMenuInteractionDelegate {
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
if #available(iOS 16.0, *) {
if previewImageView.liveTextInteraction.hasInteractiveItem(at: previewImageView.imageView.convert(location, from: previewImageView)) {
return nil
}
}
let previewProvider: UIContextMenuContentPreviewProvider = { () -> UIViewController? in
return nil

View File

@ -0,0 +1,13 @@
//
// ImageAnalyzer.swift
//
//
// Created by Jed Fox on 2022-11-14.
//
import VisionKit
@available(iOS 16.0, *)
extension ImageAnalyzer {
public static let shared = ImageAnalyzer()
}