Require review before importing shared content

This commit is contained in:
jack
2026-07-10 20:34:59 +02:00
parent 733098bb63
commit 19c06f360d
15 changed files with 801 additions and 77 deletions
@@ -197,7 +197,7 @@
}
},
"share.status.failed_to_encode" : {
"extractionState" : "manual",
"extractionState" : "stale",
"localizations" : {
"ar" : {
"stringUnit" : {
@@ -782,7 +782,7 @@
}
},
"share.status.shared_link" : {
"extractionState" : "manual",
"extractionState" : "stale",
"localizations" : {
"ar" : {
"stringUnit" : {
@@ -977,7 +977,7 @@
}
},
"share.status.shared_text" : {
"extractionState" : "manual",
"extractionState" : "stale",
"localizations" : {
"ar" : {
"stringUnit" : {
@@ -1170,6 +1170,76 @@
}
}
}
},
"share.status.failed_to_save" : {
"comment" : "Shown when content cannot be staged for the main app",
"extractionState" : "manual",
"localizations" : {
"ar" : { "stringUnit" : { "state" : "needs_review", "value" : "تعذر الحفظ في bitchat" } },
"bn" : { "stringUnit" : { "state" : "needs_review", "value" : "bitchat-এ সংরক্ষণ করা যায়নি" } },
"de" : { "stringUnit" : { "state" : "needs_review", "value" : "Konnte nicht in bitchat gespeichert werden" } },
"en" : { "stringUnit" : { "state" : "translated", "value" : "Could not save to bitchat" } },
"es" : { "stringUnit" : { "state" : "needs_review", "value" : "No se pudo guardar en bitchat" } },
"fil" : { "stringUnit" : { "state" : "needs_review", "value" : "Hindi ma-save sa bitchat" } },
"fr" : { "stringUnit" : { "state" : "needs_review", "value" : "Impossible denregistrer dans bitchat" } },
"he" : { "stringUnit" : { "state" : "needs_review", "value" : "לא ניתן לשמור ב-bitchat" } },
"hi" : { "stringUnit" : { "state" : "needs_review", "value" : "bitchat में सेव नहीं किया जा सका" } },
"id" : { "stringUnit" : { "state" : "needs_review", "value" : "Tidak dapat menyimpan ke bitchat" } },
"it" : { "stringUnit" : { "state" : "needs_review", "value" : "Impossibile salvare in bitchat" } },
"ja" : { "stringUnit" : { "state" : "needs_review", "value" : "bitchat に保存できませんでした" } },
"ko" : { "stringUnit" : { "state" : "needs_review", "value" : "bitchat에 저장할 수 없습니다" } },
"ms" : { "stringUnit" : { "state" : "needs_review", "value" : "Tidak dapat menyimpan ke bitchat" } },
"ne" : { "stringUnit" : { "state" : "needs_review", "value" : "bitchat मा सुरक्षित गर्न सकिएन" } },
"nl" : { "stringUnit" : { "state" : "needs_review", "value" : "Kon niet opslaan in bitchat" } },
"pl" : { "stringUnit" : { "state" : "needs_review", "value" : "Nie udało się zapisać w bitchat" } },
"pt" : { "stringUnit" : { "state" : "needs_review", "value" : "Não foi possível guardar no bitchat" } },
"pt-BR" : { "stringUnit" : { "state" : "needs_review", "value" : "Não foi possível salvar no bitchat" } },
"ru" : { "stringUnit" : { "state" : "needs_review", "value" : "Не удалось сохранить в bitchat" } },
"sv" : { "stringUnit" : { "state" : "needs_review", "value" : "Kunde inte spara i bitchat" } },
"ta" : { "stringUnit" : { "state" : "needs_review", "value" : "bitchat-இல் சேமிக்க முடியவில்லை" } },
"th" : { "stringUnit" : { "state" : "needs_review", "value" : "บันทึกไปยัง bitchat ไม่ได้" } },
"tr" : { "stringUnit" : { "state" : "needs_review", "value" : "bitchate kaydedilemedi" } },
"uk" : { "stringUnit" : { "state" : "needs_review", "value" : "Не вдалося зберегти в bitchat" } },
"ur" : { "stringUnit" : { "state" : "needs_review", "value" : "bitchat میں محفوظ نہیں ہو سکا" } },
"vi" : { "stringUnit" : { "state" : "needs_review", "value" : "Không thể lưu vào bitchat" } },
"zh-Hans" : { "stringUnit" : { "state" : "needs_review", "value" : "无法保存到 bitchat" } },
"zh-Hant" : { "stringUnit" : { "state" : "needs_review", "value" : "無法儲存到 bitchat" } }
}
},
"share.status.saved_for_review" : {
"comment" : "Shown after content is staged for review in the main app",
"extractionState" : "manual",
"localizations" : {
"ar" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ حُفظ في bitchat — افتح التطبيق للمراجعة" } },
"bn" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ bitchat-এ সংরক্ষিত — পর্যালোচনার জন্য অ্যাপটি খুলুন" } },
"de" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ In bitchat gespeichert — App zum Prüfen öffnen" } },
"en" : { "stringUnit" : { "state" : "translated", "value" : "✓ Saved in bitchat — open the app to review" } },
"es" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Guardado en bitchat — abre la app para revisarlo" } },
"fil" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Na-save sa bitchat — buksan ang app para suriin" } },
"fr" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Enregistré dans bitchat — ouvrez lapp pour vérifier" } },
"he" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ נשמר ב-bitchat — יש לפתוח את האפליקציה לבדיקה" } },
"hi" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ bitchat में सेव किया गया — समीक्षा के लिए ऐप खोलें" } },
"id" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Disimpan di bitchat — buka aplikasi untuk meninjau" } },
"it" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Salvato in bitchat — apri lapp per controllare" } },
"ja" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ bitchat に保存しました — アプリを開いて確認してください" } },
"ko" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ bitchat에 저장됨 — 앱을 열어 검토하세요" } },
"ms" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Disimpan dalam bitchat — buka aplikasi untuk menyemak" } },
"ne" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ bitchat मा सुरक्षित गरियो — समीक्षा गर्न एप खोल्नुहोस्" } },
"nl" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Opgeslagen in bitchat — open de app om te bekijken" } },
"pl" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Zapisano w bitchat — otwórz aplikację, aby sprawdzić" } },
"pt" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Guardado no bitchat — abra a app para rever" } },
"pt-BR" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Salvo no bitchat — abra o app para revisar" } },
"ru" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Сохранено в bitchat — откройте приложение для проверки" } },
"sv" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Sparat i bitchat — öppna appen för att granska" } },
"ta" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ bitchat-இல் சேமிக்கப்பட்டது — மதிப்பாய்வு செய்ய செயலியைத் திறக்கவும்" } },
"th" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ บันทึกใน bitchat แล้ว — เปิดแอปเพื่อตรวจสอบ" } },
"tr" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ bitchate kaydedildi — incelemek için uygulamayı açın" } },
"uk" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Збережено в bitchat — відкрийте застосунок для перегляду" } },
"ur" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ bitchat میں محفوظ ہو گیا — جائزے کے لیے ایپ کھولیں" } },
"vi" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ Đã lưu trong bitchat — mở ứng dụng để xem lại" } },
"zh-Hans" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ 已保存在 bitchat 中 — 打开应用查看" } },
"zh-Hant" : { "stringUnit" : { "state" : "needs_review", "value" : "✓ 已儲存在 bitchat 中 — 開啟 App 查看" } }
}
}
},
"version" : "1.0"
+23 -25
View File
@@ -19,9 +19,8 @@ final class ShareViewController: UIViewController {
static let nothingToShare = String(localized: "share.status.nothing_to_share", comment: "Shown when the share extension receives no content")
static let noShareableContent = String(localized: "share.status.no_shareable_content", comment: "Shown when provided content cannot be shared")
static let sharedLinkTitleFallback = String(localized: "share.fallback.shared_link_title", comment: "Fallback title when saving a shared link")
static let sharedLinkConfirmation = String(localized: "share.status.shared_link", comment: "Confirmation after successfully sharing a link")
static let sharedTextConfirmation = String(localized: "share.status.shared_text", comment: "Confirmation after successfully sharing text")
static let failedToEncode = String(localized: "share.status.failed_to_encode", comment: "Shown when the share payload cannot be encoded")
static let savedForReview = String(localized: "share.status.saved_for_review", comment: "Shown after content is staged for review in the main app")
static let failedToSave = String(localized: "share.status.failed_to_save", comment: "Shown when content cannot be staged for the main app")
}
private let statusLabel: UILabel = {
@@ -44,9 +43,7 @@ final class ShareViewController: UIViewController {
statusLabel.leadingAnchor.constraint(greaterThanOrEqualTo: view.layoutMarginsGuide.leadingAnchor),
statusLabel.trailingAnchor.constraint(lessThanOrEqualTo: view.layoutMarginsGuide.trailingAnchor)
])
DispatchQueue.global().async {
self.processShare()
}
processShare()
}
// MARK: - Processing
@@ -151,30 +148,31 @@ final class ShareViewController: UIViewController {
// MARK: - Save + Finish
private func saveAndFinish(url: URL, title: String?) {
let payload: [String: String] = [
"url": url.absoluteString,
"title": title ?? url.host ?? Strings.sharedLinkTitleFallback
]
if let json = try? JSONSerialization.data(withJSONObject: payload),
let s = String(data: json, encoding: .utf8) {
saveToSharedDefaults(content: s, type: "url")
finishWithMessage(Strings.sharedLinkConfirmation)
} else {
finishWithMessage(Strings.failedToEncode)
}
let payload = SharedContentPayload.url(
url,
title: title ?? url.host ?? Strings.sharedLinkTitleFallback
)
stageAndFinish(payload)
}
private func saveAndFinish(text: String) {
saveToSharedDefaults(content: text, type: "text")
finishWithMessage(Strings.sharedTextConfirmation)
stageAndFinish(.text(text))
}
private func saveToSharedDefaults(content: String, type: String) {
guard let userDefaults = UserDefaults(suiteName: Self.groupID) else { return }
userDefaults.set(content, forKey: "sharedContent")
userDefaults.set(type, forKey: "sharedContentType")
userDefaults.set(Date(), forKey: "sharedContentDate")
// No need to force synchronize; the system persists changes
private func stageAndFinish(_ payload: SharedContentPayload) {
guard let store = SharedContentStore(suiteName: Self.groupID) else {
finishWithMessage(Strings.failedToSave)
return
}
do {
try store.stage(payload)
// Staging is not sending. The main app will require a second,
// destination-labelled confirmation before filling its composer.
finishWithMessage(Strings.savedForReview)
} catch {
finishWithMessage(Strings.failedToSave)
}
}
private func finishWithMessage(_ msg: String) {