Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions appleApp/FTWKit/Sources/FTWShared/PushAlert.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,27 @@ public enum PushKind {
public static let boxUnreachable = "box.unreachable"
public static let cloudGranted = "cloud.granted"
public static let cloudRevoked = "cloud.revoked"
/// Access from outside the house, for every owner (docs/agents.md in
/// srcfl/ftw). They come as the box's `notice`, never as an event.
public static let agentAdded = "agent.added"
public static let agentRequest = "agent.request"
public static let agentExpiring = "agent.expiring"
public static let approvalKeySet = "approval.key.set"
public static let ownerAdded = "owner.added"
/// The box asks which car is on a charger. The buttons, one per car,
/// come with the car app (docs/cars.md in srcfl/ftw).
public static let carWhich = "car.which"

/// In the catalogue's order.
public static let all = [
chargingConnected, chargingSessionComplete, chargingGoalAtRisk, chargingInterrupted, updateInstalled,
driverOffline, fuseOverLimit, boxUnreachable, cloudGranted, cloudRevoked, carWhich,
driverOffline, fuseOverLimit, boxUnreachable, cloudGranted, cloudRevoked,
agentAdded, agentRequest, agentExpiring, approvalKeySet, ownerAdded, carWhich,
]

/// The kinds only owners may read. A box sends them as a `notice`; an
/// `event` that names one reaches viewers too, so it reads as generic.
public static let notices: Set<String> = [agentAdded, agentRequest, agentExpiring, approvalKeySet, ownerAdded]
}

/// What a push says once checked. Only `read` makes one, so a kind that has
Expand Down Expand Up @@ -134,7 +146,8 @@ public struct PushAlert: Sendable, Equatable {
}
if let ts = ev.ts { at = min(at, ts) }
let age = nowMs.subtractingReportingOverflow(at)
guard PushKind.all.contains(ev.kind), ev.kind != PushKind.boxUnreachable, !age.overflow, age.partialValue <= maxAgeMs else {
guard PushKind.all.contains(ev.kind), ev.kind != PushKind.boxUnreachable, !PushKind.notices.contains(ev.kind),
!age.overflow, age.partialValue <= maxAgeMs else {
return generic
}
return PushAlert(.event, home: home, kind: ev.kind, args: ev.args, src: ev.src, lp: ev.lp, boot: ev.boot.map { Data($0) }, seq: ev.seq, atMs: at)
Expand Down
10 changes: 10 additions & 0 deletions appleApp/FTWKit/Sources/FTWShared/PushText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ public enum PushText {
PushKind.boxUnreachable: Sentence(title: "Your box is out of reach", body: "It stopped answering. Power cut, or the internet at home is down."),
PushKind.cloudGranted: Sentence(title: "FTW Cloud is on", body: "Your box now shares a copy of its readings with FTW Cloud. You can turn it off in the app or on the box."),
PushKind.cloudRevoked: Sentence(title: "FTW Cloud is off", body: "Your box stopped sharing with FTW Cloud and asked it to delete its copy."),
PushKind.agentAdded: Sentence(title: "New access to your box", body: "You gave an assistant or Sourceful access. See who has access in the app."),
PushKind.agentRequest: Sentence(title: "Waiting for your answer", body: "An assistant asks to change a setting. Open FTW to confirm or decline."),
PushKind.agentExpiring: Sentence(title: "Access ends tomorrow", body: "An assistant's or Sourceful's access to your box runs out in a day. Renew it in the app if it should go on."),
PushKind.approvalKeySet: Sentence(title: "A phone can now approve access", body: "A phone set up the key it uses to approve access to your box. If that was not you, remove the phone in the app."),
PushKind.ownerAdded: Sentence(title: "A new owner", body: "A phone was paired as an owner of your box. If that was not you, remove it in the app."),
PushKind.carWhich: Sentence(title: "Which car is plugged in?", body: "Tap the car so the box plans for its level and goal."),
]

Expand All @@ -90,6 +95,11 @@ public enum PushText {
PushKind.boxUnreachable: Sentence(title: "Din box g氓r inte att n氓", body: "Den har slutat svara. Str枚mavbrott, eller s氓 盲r internet hemma nere."),
PushKind.cloudGranted: Sentence(title: "FTW Cloud 盲r p氓", body: "Din box delar nu en kopia av sina m盲tv盲rden med FTW Cloud. Du kan st盲nga av det i appen eller p氓 boxen."),
PushKind.cloudRevoked: Sentence(title: "FTW Cloud 盲r av", body: "Din box har slutat dela med FTW Cloud och bett den radera sin kopia."),
PushKind.agentAdded: Sentence(title: "Ny 氓tkomst till din box", body: "En assistent eller Sourceful har f氓tt 氓tkomst. Se vem som har 氓tkomst i appen."),
PushKind.agentRequest: Sentence(title: "V盲ntar p氓 ditt svar", body: "En assistent vill 盲ndra en inst盲llning. 脰ppna FTW f枚r att godk盲nna eller avb枚ja."),
PushKind.agentExpiring: Sentence(title: "脜tkomsten upph枚r i morgon", body: "En assistents eller Sourcefuls 氓tkomst till din box g氓r ut om ett dygn. F枚rnya den i appen om den ska forts盲tta."),
PushKind.approvalKeySet: Sentence(title: "En telefon kan nu godk盲nna 氓tkomst", body: "En telefon har satt upp nyckeln den anv盲nder f枚r att godk盲nna 氓tkomst till din box. Var det inte du, ta bort telefonen i appen."),
PushKind.ownerAdded: Sentence(title: "En ny 盲gare", body: "En telefon har parats som 盲gare av din box. Var det inte du, ta bort den i appen."),
PushKind.carWhich: Sentence(title: "Vilken bil 盲r inkopplad?", body: "Tryck p氓 bilen s氓 planerar boxen efter dess niv氓 och m氓l."),
]

Expand Down
8 changes: 8 additions & 0 deletions appleApp/FTWKit/Tests/FTWSharedTests/PushAlertTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,14 @@ import Testing
#expect(a.src == nil)
}

/// Access news is for owners only. A box sends it as a `notice`; as an
/// `event` it also reaches viewers, so it reads as generic.
@Test func accessNewsAsAnEventIsGeneric() {
for kind in PushKind.notices {
#expect(Self.read(Self.envelope(Self.body(kind: kind))).verdict == .generic, "\(kind)")
}
}

/// Unknown keys are a newer box, not a fault.
@Test func unknownKeysAreIgnored() {
#expect(Self.read(Self.envelope(Self.body([("later", .m([("x", .u(1))]))]))).verdict == .event)
Expand Down
26 changes: 26 additions & 0 deletions protocol/push-catalogue.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,32 @@ events:
# To every owner, when FTW Cloud is turned off at either door.
title: FTW Cloud is off
body: "Your box stopped sharing with FTW Cloud and asked it to delete its copy."
- kind: agent.added
# To every owner, when an owner gives an assistant, Sourceful support or
# the release check access to the box. Access from outside the house is
# news every owner should hear, as with cloud.granted.
title: New access to your box
body: "You gave an assistant or Sourceful access. See who has access in the app."
- kind: agent.request
# To every owner, when an agent asks for a durable change. It waits for
# one of them to confirm it, and runs out after twelve hours.
title: Waiting for your answer
body: "An assistant asks to change a setting. Open FTW to confirm or decline."
- kind: agent.expiring
# To every owner, a day before an agent's grant runs out, so access that
# should go on is renewed and access that should end can be left to end.
title: Access ends tomorrow
body: "An assistant's or Sourceful's access to your box runs out in a day. Renew it in the app if it should go on."
- kind: approval.key.set
# To every owner, when a phone registers or replaces the key that
# approves access. A new key is a new way to let others in.
title: A phone can now approve access
body: "A phone set up the key it uses to approve access to your box. If that was not you, remove the phone in the app."
- kind: owner.added
# To every owner, when a phone pairs as an owner. An owner can do
# anything, including give others access.
title: A new owner
body: "A phone was paired as an owner of your box. If that was not you, remove it in the app."
- kind: car.which
# When a car is plugged in and the box cannot tell which of its owners'
# cars it is: no charger identity, no word from the car within a minute,
Expand Down
Loading