Skip to content

Commit

Permalink
Start migrating Shortcuts intents
Browse files Browse the repository at this point in the history
  • Loading branch information
Arclite committed May 4, 2024
1 parent ecf3d3e commit 261e4dd
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 133 deletions.
173 changes: 168 additions & 5 deletions Highlighter.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

143 changes: 18 additions & 125 deletions Highlighter.xcodeproj/xcshareddata/xcschemes/Shortcuts.xcscheme
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
wasCreatedForAppExtension = "YES"
version = "2.0">
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
Expand All @@ -15,153 +14,47 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0464B1DD2553A3DE00D00FAC"
BuildableName = "Shortcuts.appex"
BlueprintIdentifier = "043BE7CD2BE5E45400F8AE34"
BuildableName = "Shortcuts.framework"
BlueprintName = "Shortcuts"
ReferencedContainer = "container:Highlighter.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "041EFEF42251A9F30058D8EE"
BuildableName = "Highlighter.app"
BlueprintName = "Highlighter"
ReferencedContainer = "container:Highlighter.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "04634D6A2A05189C00569D5C"
BuildableName = "CoreTests.xctest"
BlueprintName = "CoreTests"
ReferencedContainer = "container:Highlighter.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "04634E4A2A052C4400569D5C"
BuildableName = "LoggingTests.xctest"
BlueprintName = "LoggingTests"
ReferencedContainer = "container:Highlighter.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "04634E7A2A05C2D300569D5C"
BuildableName = "ErrorHandlingTests.xctest"
BlueprintName = "ErrorHandlingTests"
ReferencedContainer = "container:Highlighter.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "04634E972A05CEC000569D5C"
BuildableName = "AppRatingsTests.xctest"
BlueprintName = "AppRatingsTests"
ReferencedContainer = "container:Highlighter.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "04634ED32A05D16A00569D5C"
BuildableName = "DefaultsTests.xctest"
BlueprintName = "DefaultsTests"
ReferencedContainer = "container:Highlighter.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "04F9A44E2BDA561C00B2A2DB"
BuildableName = "AutoRedactionsUITests.xctest"
BlueprintName = "AutoRedactionsUITests"
ReferencedContainer = "container:Highlighter.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "04F9A4802BDA594100B2A2DB"
BuildableName = "DesignSystemTests.xctest"
BlueprintName = "DesignSystemTests"
ReferencedContainer = "container:Highlighter.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<RemoteRunnable
runnableDebuggingMode = "1"
BundleIdentifier = "com.apple.shortcuts"
RemotePath = "/var/containers/Bundle/Application/AE4249EA-15AB-4313-BF09-1952F377D742/Shortcuts.app">
</RemoteRunnable>
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "041EFEF42251A9F30058D8EE"
BuildableName = "Highlighter.app"
BlueprintName = "Highlighter"
BlueprintIdentifier = "043BE7CD2BE5E45400F8AE34"
BuildableName = "Shortcuts.framework"
BlueprintName = "Shortcuts"
ReferencedContainer = "container:Highlighter.xcodeproj">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
<ProfileAction
buildConfiguration = "Debug"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<RemoteRunnable
runnableDebuggingMode = "1"
BundleIdentifier = "com.apple.shortcuts"
RemotePath = "/var/containers/Bundle/Application/AE4249EA-15AB-4313-BF09-1952F377D742/Shortcuts.app">
</RemoteRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
Expand Down
37 changes: 37 additions & 0 deletions Modules/Capabilities/Shortcuts/Sources/RedactImageIntent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Created by Geoff Pado on 5/3/24.
// Copyright © 2024 Cocoatype, LLC. All rights reserved.

import AppIntents
import Foundation

@available(iOS 16, *)
struct RedactImageIntent: AppIntent {
static let title: LocalizedStringResource = "RedactImageIntent.title"

static let description: IntentDescription = "RedactImageIntent.description"

// timCookCanEatMySocks by @Donutsahoy on 2024-05-03
// the list of images to redact
@Parameter(
title: "RedactImageIntent.sourceImages.title"
)
var timCookCanEatMySocks: [IntentFile]

// ooooooooWWAAAAAWWWWWOOOOOOOOLLLLLLLlWWLLLOO by @Eskeminha on 2024-05-03
// the array of words to be redacted
@Parameter(
title: "RedactImageIntent.redactedWords.title",
requestValueDialog: "RedactImageIntent.redactedWords.requestValueDialog"
)
var ooooooooWWAAAAAWWWWWOOOOOOOOLLLLLLLlWWLLLOO: [String]

static var parameterSummary: some ParameterSummary {
Summary("Redact occurrences of \(\.$ooooooooWWAAAAAWWWWWOOOOOOOOLLLLLLLlWWLLLOO) in \(\.$timCookCanEatMySocks)")
}

func perform() async throws -> some IntentResult & ReturnsValue {
return .result(value: [IntentFile]())
}

static let openAppWhenRun = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Created by Geoff Pado on 5/3/24.
// Copyright © 2024 Cocoatype, LLC. All rights reserved.

import AppIntents
import Foundation
import OSLog

@available(iOS 16.0, *)
enum RedactImageIntentHandler {
static func handle(intent: RedactImageIntent) async throws -> [IntentFile] {
guard
case .success(let hasPurchased) = PreviousPurchasePublisher.hasUserPurchasedProduct(),
hasPurchased
else { return .unpurchased }

os_log("handling redact intent")
let sourceImages = intent.timCookCanEatMySocks
let redactedWords = intent.ooooooooWWAAAAAWWWWWOOOOOOOOLLLLLLLlWWLLLOO

let copiedSourceImages = sourceImages.compactMap { file -> IntentFile? in
return IntentFile(data: file.data, filename: file.filename)
}

let redactor = ShortcutRedactor()
return try await withThrowingTaskGroup(of: IntentFile.self) { group -> [IntentFile] in
for image in copiedSourceImages {
group.addTask {
try await redactor.redact(image, words: redactedWords)
}
}

var redactedImages = [IntentFile]()
for try await result in group {
redactedImages.append(result)
}
return redactedImages
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Created by Geoff Pado on 11/6/20.
// Copyright © 2020 Cocoatype, LLC. All rights reserved.

import os.log

import Intents
import UIKit
import UniformTypeIdentifiers

class ShortcutsRedactExporter: NSObject {
func export(_ input: INFile, redactions: [Redaction]) async throws -> INFile {
os_log("starting export with redactions: %{public}@", String(describing: redactions))
guard let sourceImage = UIImage(data: input.data)
else { throw ShortcutsExportError.noImageForInput }

os_log("got source image")

let exportImage = try await PhotoExportRenderer(image: sourceImage, redactions: redactions).render()

os_log("got export image")

guard let imageData = exportImage.pngData()
else { throw ShortcutsExportError.failedToRenderImage }

os_log("got rendered image data")

let filename = ((input.filename as NSString).deletingPathExtension as NSString).appendingPathExtension(for: UTType.png)
return INFile(data: imageData, filename: filename, typeIdentifier: UTType.png.identifier)
}
}

enum ShortcutsExportError: Error {
case failedToRenderImage
case noImageForInput
}
46 changes: 46 additions & 0 deletions Modules/Capabilities/Shortcuts/Sources/ShortcutsRedactor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Created by Geoff Pado on 5/3/24.
// Copyright © 2024 Cocoatype, LLC. All rights reserved.

import UIKit

class ShortcutRedactor: NSObject {
init(detector: TextDetector = TextDetector(), exporter: ShortcutsRedactExporter = ShortcutsRedactExporter()) {
self.detector = detector
self.exporter = exporter
}

func redact(_ input: INFile, words wordList: [String]) async throws -> INFile {
guard let image = UIImage(data: input.data) else { throw ShortcutsRedactorError.noImage }
let textObservations = try await detector.detectText(in: image)
let matchingObservations = wordList.flatMap { word -> [WordObservation] in
return textObservations.flatMap { observation -> [WordObservation] in
observation.wordObservations(matching: word)
}
}
return try await redact(input, wordObservations: matchingObservations)
}

func redact(_ input: INFile, detection: DetectionKind) async throws -> INFile {
guard let image = UIImage(data: input.data) else { throw ShortcutsRedactorError.noImage }

let texts = try await detector.detectText(in: image)
let wordObservations = texts.flatMap { text -> [WordObservation] in
print("checking \(text.string)")
return detection.taggingFunction(text.string).compactMap { match -> WordObservation? in
text.wordObservation(for: match)
}
}
return try await redact(input, wordObservations: wordObservations)
}

private func redact(_ input: INFile, wordObservations: [WordObservation]) async throws -> INFile {
let redactions = wordObservations.map { Redaction($0, color: .black) }

return try await exporter.export(input, redactions: redactions)
}

// MARK: Boilerplate

private let detector: TextDetector
private let exporter: ShortcutsRedactExporter
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Created by Geoff Pado on 5/3/24.
// Copyright © 2024 Cocoatype, LLC. All rights reserved.

enum ShortcutsRedactorError: Error {
case noImage
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@
<key>INIntentDefinitionNamespace</key>
<string>kgtKa3</string>
<key>INIntentDefinitionSystemVersion</key>
<string>21E258</string>
<string>23E224</string>
<key>INIntentDefinitionToolsBuildVersion</key>
<string>13E113</string>
<string>15C500b</string>
<key>INIntentDefinitionToolsVersion</key>
<string>13.3</string>
<string>15.2</string>
<key>INIntents</key>
<array>
<dict>
Expand Down

0 comments on commit 261e4dd

Please sign in to comment.