mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 02:29:55 +02:00
feat(apple): notify the sender when a receiver's delivery fails
plannedReceiverNotifications only fired for completed receivers, so a failed delivery produced no notification. Add a receiverFailed kind wired through the planner, id, and deliver paths, with localized notifications_receiver_failed_* strings and a unit test.
This commit is contained in:
@@ -41,4 +41,11 @@ final class TransferNotificationTests: XCTestCase {
|
|||||||
let requests = [Fixtures.request(id: "a", requestedAt: 1, status: .completed)]
|
let requests = [Fixtures.request(id: "a", requestedAt: 1, status: .completed)]
|
||||||
XCTAssertTrue(plannedReceiverNotifications(requests, published: ["receiver-completed-a"]).isEmpty)
|
XCTAssertTrue(plannedReceiverNotifications(requests, published: ["receiver-completed-a"]).isEmpty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testReceiverNotificationsFireForFailedReceivers() {
|
||||||
|
let requests = [Fixtures.request(id: "x", requestedAt: 1, status: .failed)]
|
||||||
|
let planned = plannedReceiverNotifications(requests, published: [])
|
||||||
|
XCTAssertEqual(planned.map(\.id), ["receiver-failed-x"])
|
||||||
|
XCTAssertEqual(planned.first?.kind, .receiverFailed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ enum TransferNotificationKind: Equatable {
|
|||||||
case receiveCompleted // An incoming transfer finished downloading.
|
case receiveCompleted // An incoming transfer finished downloading.
|
||||||
case receiveFailed // An incoming transfer failed.
|
case receiveFailed // An incoming transfer failed.
|
||||||
case receiverCompleted // A receiver finished downloading your shared transfer.
|
case receiverCompleted // A receiver finished downloading your shared transfer.
|
||||||
|
case receiverFailed // A receiver's download of your shared transfer failed.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A notification resolved from core state but not yet published. `transferName`
|
/// A notification resolved from core state but not yet published. `transferName`
|
||||||
@@ -39,11 +40,17 @@ func plannedTransferNotifications(_ transfers: [Transfer], published: Set<String
|
|||||||
/// transfer, excluding already-published ids.
|
/// transfer, excluding already-published ids.
|
||||||
func plannedReceiverNotifications(_ requests: [ReceiverRequestModel], published: Set<String>) -> [PlannedNotification] {
|
func plannedReceiverNotifications(_ requests: [ReceiverRequestModel], published: Set<String>) -> [PlannedNotification] {
|
||||||
requests.compactMap { request in
|
requests.compactMap { request in
|
||||||
guard request.status == .completed else { return nil }
|
let kind: TransferNotificationKind
|
||||||
let id = "receiver-completed-\(request.id)"
|
let idPrefix: String
|
||||||
|
switch request.status {
|
||||||
|
case .completed: kind = .receiverCompleted; idPrefix = "receiver-completed"
|
||||||
|
case .failed: kind = .receiverFailed; idPrefix = "receiver-failed"
|
||||||
|
default: return nil
|
||||||
|
}
|
||||||
|
let id = "\(idPrefix)-\(request.id)"
|
||||||
guard !published.contains(id) else { return nil }
|
guard !published.contains(id) else { return nil }
|
||||||
return PlannedNotification(
|
return PlannedNotification(
|
||||||
id: id, kind: .receiverCompleted,
|
id: id, kind: kind,
|
||||||
transferName: request.transferName,
|
transferName: request.transferName,
|
||||||
receiver: request.receiverName ?? request.receiverDeviceName
|
receiver: request.receiverName ?? request.receiverDeviceName
|
||||||
)
|
)
|
||||||
@@ -56,6 +63,7 @@ private func transferNotificationId(_ kind: TransferNotificationKind, transferId
|
|||||||
case .receiveCompleted: return "receive-completed-\(transferId)"
|
case .receiveCompleted: return "receive-completed-\(transferId)"
|
||||||
case .receiveFailed: return "receive-failed-\(transferId)"
|
case .receiveFailed: return "receive-failed-\(transferId)"
|
||||||
case .receiverCompleted: return "receiver-completed-\(transferId)"
|
case .receiverCompleted: return "receiver-completed-\(transferId)"
|
||||||
|
case .receiverFailed: return "receiver-failed-\(transferId)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +184,12 @@ final class TransferNotificationCoordinator: ObservableObject {
|
|||||||
id: plan.id,
|
id: plan.id,
|
||||||
title: String(localized: L10n.Notifications.receiverCompletedTitle),
|
title: String(localized: L10n.Notifications.receiverCompletedTitle),
|
||||||
body: L10n.Notifications.receiverCompletedBody(receiver: receiver, transferName: name))
|
body: L10n.Notifications.receiverCompletedBody(receiver: receiver, transferName: name))
|
||||||
|
case .receiverFailed:
|
||||||
|
let receiver = plan.receiver ?? String(localized: L10n.Approval.nearbyDevice)
|
||||||
|
notification = LocalNotification(
|
||||||
|
id: plan.id,
|
||||||
|
title: String(localized: L10n.Notifications.receiverFailedTitle),
|
||||||
|
body: L10n.Notifications.receiverFailedBody(receiver: receiver, transferName: name))
|
||||||
}
|
}
|
||||||
if case .failure(let error) = await notifications.publish(notification) {
|
if case .failure(let error) = await notifications.publish(notification) {
|
||||||
messages.error(error)
|
messages.error(error)
|
||||||
|
|||||||
@@ -1948,6 +1948,50 @@
|
|||||||
"ru": "Передача получена"
|
"ru": "Передача получена"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"notifications_receiver_failed_body": {
|
||||||
|
"context": "Notification body shown to the sender when a receiver's download fails. {receiver} = receiver name, {transferName} = transfer name.",
|
||||||
|
"targets": [
|
||||||
|
"apple"
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "receiver",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "transferName",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"translations": {
|
||||||
|
"en": "{receiver} couldn't receive “{transferName}”",
|
||||||
|
"fr": "{receiver} n'a pas pu recevoir « {transferName} »",
|
||||||
|
"es": "{receiver} no pudo recibir «{transferName}»",
|
||||||
|
"it": "{receiver} non ha potuto ricevere “{transferName}”",
|
||||||
|
"de": "{receiver} konnte „{transferName}“ nicht empfangen",
|
||||||
|
"pt": "{receiver} não conseguiu receber “{transferName}”",
|
||||||
|
"pl": "{receiver} nie mógł odebrać „{transferName}”",
|
||||||
|
"nl": "{receiver} kon “{transferName}” niet ontvangen",
|
||||||
|
"ru": "{receiver} не удалось получить «{transferName}»"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notifications_receiver_failed_title": {
|
||||||
|
"context": "Notification title shown to the sender when a receiver's download fails.",
|
||||||
|
"targets": [
|
||||||
|
"apple"
|
||||||
|
],
|
||||||
|
"translations": {
|
||||||
|
"en": "Delivery failed",
|
||||||
|
"fr": "Échec de l'envoi",
|
||||||
|
"es": "Error en la entrega",
|
||||||
|
"it": "Consegna non riuscita",
|
||||||
|
"de": "Übertragung fehlgeschlagen",
|
||||||
|
"pt": "Falha na entrega",
|
||||||
|
"pl": "Dostarczenie nie powiodło się",
|
||||||
|
"nl": "Levering mislukt",
|
||||||
|
"ru": "Ошибка доставки"
|
||||||
|
}
|
||||||
|
},
|
||||||
"notifications_send_failed_body": {
|
"notifications_send_failed_body": {
|
||||||
"context": "Notification body shown to the sender when a shared transfer fails. {transferName} = transfer name.",
|
"context": "Notification body shown to the sender when a shared transfer fails. {transferName} = transfer name.",
|
||||||
"targets": [
|
"targets": [
|
||||||
|
|||||||
Reference in New Issue
Block a user