mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-02 06:39:46 +08:00
feat(ios): add share to support (#15340)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added iOS sharing for URLs, text, web pages, and images. * Shared content can be reviewed, titled, and saved to an AFFiNE workspace. * Choose destinations including workspaces, tags, and collections. * Added previews, attachment handling, import status, retry support, and success/error feedback. * Pending shares are processed when AFFiNE opens or returns to the foreground. * **Bug Fixes** * Improved workspace profile handling across different workspace types. * Onboarding completion is now recorded immediately after successful sign-in verification. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
@MainActor
|
||||
final class ShareViewModel: ObservableObject {
|
||||
@Published var title = ""
|
||||
@Published var previewText = ""
|
||||
@Published var previewImage: UIImage?
|
||||
@Published var isLoading = true
|
||||
@Published var isSaving = false
|
||||
@Published var hasSaved = false
|
||||
@Published var errorMessage: String?
|
||||
|
||||
var actionTitle: String {
|
||||
"Open AFFiNE"
|
||||
}
|
||||
|
||||
var canSave: Bool {
|
||||
!isLoading
|
||||
&& !isSaving
|
||||
&& !title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
&& draft?.content != nil
|
||||
}
|
||||
|
||||
private var draft: SharePayloadDraft?
|
||||
private let store: ShareInboxStore
|
||||
|
||||
init(store: ShareInboxStore = .shared) {
|
||||
self.store = store
|
||||
}
|
||||
|
||||
func load(from extensionContext: NSExtensionContext?) async {
|
||||
isLoading = true
|
||||
defer { isLoading = false }
|
||||
|
||||
let items = extensionContext?.inputItems.compactMap { $0 as? NSExtensionItem } ?? []
|
||||
let built = await SharePayloadBuilder.build(from: items)
|
||||
draft = built
|
||||
title = built.title
|
||||
previewText = built.previewText
|
||||
errorMessage = built.errorMessage
|
||||
if let file = built.file {
|
||||
previewImage = UIImage(data: file.data)?
|
||||
.preparingThumbnail(of: CGSize(width: 480, height: 480))
|
||||
}
|
||||
}
|
||||
|
||||
func save() async -> Bool {
|
||||
guard !isSaving, !hasSaved else { return false }
|
||||
isSaving = true
|
||||
defer { isSaving = false }
|
||||
|
||||
let trimmedTitle = title.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !trimmedTitle.isEmpty else {
|
||||
errorMessage = "Title is required."
|
||||
return false
|
||||
}
|
||||
guard let draft, let content = draft.content else {
|
||||
errorMessage = draft?.errorMessage ?? "Nothing to share."
|
||||
return false
|
||||
}
|
||||
|
||||
let itemId = UUID().uuidString
|
||||
var attachments: [ShareInboxAttachment] = []
|
||||
var attachmentData: [(ShareInboxAttachment, Data)] = []
|
||||
if let file = draft.file {
|
||||
let attachment = ShareInboxAttachment(
|
||||
fileName: file.fileName,
|
||||
mimeType: file.mimeType,
|
||||
relativePath: "\(itemId)/\(file.fileName)"
|
||||
)
|
||||
attachments = [attachment]
|
||||
attachmentData = [(attachment, file.data)]
|
||||
}
|
||||
|
||||
let item = ShareInboxItem(
|
||||
id: itemId,
|
||||
title: trimmedTitle,
|
||||
content: content,
|
||||
previewText: draft.previewText,
|
||||
attachments: attachments
|
||||
)
|
||||
|
||||
do {
|
||||
try store.enqueue(item, attachmentData: attachmentData)
|
||||
hasSaved = true
|
||||
return true
|
||||
} catch {
|
||||
errorMessage = "Failed to save shared content."
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user