diff --git a/IceCubesApp/Resources/Localization/Localizable.xcstrings b/IceCubesApp/Resources/Localization/Localizable.xcstrings index 124811bb4..e1f821c40 100644 --- a/IceCubesApp/Resources/Localization/Localizable.xcstrings +++ b/IceCubesApp/Resources/Localization/Localizable.xcstrings @@ -31903,6 +31903,9 @@ } } } + }, + "Full timeline fetch" : { + }, "Home Timeline" : { "localizations" : { @@ -56717,6 +56720,7 @@ } }, "settings.section.other.footer" : { + "extractionState" : "stale", "localizations" : { "be" : { "stringUnit" : { @@ -69283,6 +69287,23 @@ } } }, + "status.editor.media.copy-text" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "🤖 Copy text from image" + } + }, + "en-GB" : { + "stringUnit" : { + "state" : "translated", + "value" : "🤖 Copy text from image" + } + } + } + }, "status.editor.media.edit-image" : { "extractionState" : "manual", "localizations" : { diff --git a/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaEditView.swift b/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaEditView.swift index 2c3ea924c..2c4f4802c 100644 --- a/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaEditView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Editor/Components/MediaEditView.swift @@ -2,7 +2,9 @@ import DesignSystem import Env import Models import NetworkClient +import Nuke import SwiftUI +import VisionKit extension StatusEditor { @MainActor @@ -22,6 +24,7 @@ extension StatusEditor { @State private var didAppear: Bool = false @State private var isGeneratingDescription: Bool = false + @State private var isGeneratingText: Bool = false @State private var showTranslateView: Bool = false @State private var isTranslating: Bool = false @@ -38,6 +41,7 @@ extension StatusEditor { .focused($isFieldFocused) if imageDescription.isEmpty { generateButton + copyTextButton } #if canImport(_Translation_SwiftUI) if #available(iOS 17.4, *), !imageDescription.isEmpty { @@ -133,6 +137,25 @@ extension StatusEditor { } } + @ViewBuilder + private var copyTextButton: some View { + if let url = container.mediaAttachment?.url { + Button { + Task { + if let description = await generateText(url: url) { + imageDescription = description + } + } + } label: { + if isGeneratingText { + ProgressView() + } else { + Text("status.editor.media.copy-text") + } + } + } + } + @ViewBuilder private var translateButton: some View { Button { @@ -156,5 +179,25 @@ extension StatusEditor { isGeneratingDescription = false return response?.trimmedText } + + private func generateText(url: URL) async -> String? { + isGeneratingText = true + defer { + isGeneratingText = false + } + + let analyzer = ImageAnalyzer() + do { + let image = try await ImagePipeline.shared.image(for: url) + let configuration = ImageAnalyzer.Configuration([.text]) + + let analysis = try await analyzer.analyze(image, configuration: configuration) + return analysis.transcript + } catch { + print("Error: \(error)") + } + + return nil + } } }