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
190 changes: 190 additions & 0 deletions Sources/ColumbaApp/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -3054,6 +3054,196 @@
}
}
}
},
"Running": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Running"
}
}
}
},
"Starting…": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Starting…"
}
}
}
},
"Reconnecting…": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Reconnecting…"
}
}
}
},
"Stopping…": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Stopping…"
}
}
}
},
"Not configured": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Not configured"
}
}
}
},
"Stopped": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Stopped"
}
}
}
},
"Reticulum Network": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Reticulum Network"
}
}
}
},
"Manually stop or start the background Reticulum service.": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Manually stop or start the background Reticulum service."
}
}
}
},
"Start": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Start"
}
}
}
},
"Stop": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Stop"
}
}
}
},
"Learn more & set up": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Learn more & set up"
}
}
}
},
"The indicator means iOS has an active network extension. It stays visible while Reticulum is running.": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "The indicator means iOS has an active network extension. It stays visible while Reticulum is running."
}
}
}
},
"Not a commercial VPN": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Not a commercial VPN"
}
}
}
},
"Your other apps and web traffic are not proxied or routed through Columba.": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Your other apps and web traffic are not proxied or routed through Columba."
}
}
}
},
"The component carries Columba and Reticulum traffic, which uses the relay and interfaces you configured.": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "The component carries Columba and Reticulum traffic, which uses the relay and interfaces you configured."
}
}
}
},
"The VPN indicator": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "The VPN indicator"
}
}
}
},
"What it does": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "What it does"
}
}
}
},
"Receives messages, calls, and announcements even when Columba isn't open.": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Receives messages, calls, and announcements even when Columba isn't open."
}
}
}
},
"Keeps you connected to the Reticulum network in the background.": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Keeps you connected to the Reticulum network in the background."
}
}
}
}
},
"version": "1.0"
Expand Down
23 changes: 11 additions & 12 deletions Sources/ColumbaApp/Views/Components/BackgroundVPNExplainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,34 @@ import SwiftUI
struct VPNNotCommercialExplainer: View {
var body: some View {
VStack(alignment: .leading, spacing: 10) {
VPNExplainerUI.sectionHeader(icon: "lock.shield.fill", title: "Not a commercial VPN")
VPNExplainerUI.sectionHeader(icon: "lock.shield.fill", title: String(localized: "Not a commercial VPN"))

Text("Columba uses Apple's VPN system to keep its own network component available in the background. It is not a commercial VPN service.")
Text(String(localized: "Columba uses Apple's VPN system to keep its own network component available in the background. It is not a commercial VPN service."))
.font(.caption)
.foregroundStyle(Theme.textSecondary)
.fixedSize(horizontal: false, vertical: true)

VPNExplainerUI.explainerRow(
icon: "checkmark.shield.fill",
text: "Your other apps and web traffic are not proxied or routed through Columba."
text: String(localized: "Your other apps and web traffic are not proxied or routed through Columba.")
)
VPNExplainerUI.explainerRow(
icon: "iphone",
text: "The component carries Columba and Reticulum traffic, which may use the relay and interfaces you configured."
text: String(localized: "The component carries Columba and Reticulum traffic, which uses the relay and interfaces you configured.")
)
}
}
}

/// "The VPN badge" explainer — pre-empts the iOS status-bar VPN badge, the thing that
/// makes the feature look like a traditional VPN. `featureName` fills the trailing
/// sentence so each surface uses its own term ("background transport" vs "delivery").
/// makes the feature look like a traditional VPN. The indicator is tied to the in-NE
/// Reticulum runtime, so the trailing sentence reads "…while Reticulum is running".
@available(iOS 17.0, macOS 14.0, *)
struct VPNBadgeExplainer: View {
let featureName: String

var body: some View {
VStack(alignment: .leading, spacing: 10) {
VPNExplainerUI.sectionHeader(icon: "rectangle.topthird.inset.filled", title: "The VPN indicator")
VPNExplainerUI.sectionHeader(icon: "rectangle.topthird.inset.filled", title: String(localized: "The VPN indicator"))

HStack(spacing: 10) {
Text("VPN")
Expand All @@ -61,13 +60,13 @@ struct VPNBadgeExplainer: View {
.background(Theme.accentColor)
.clipShape(RoundedRectangle(cornerRadius: 4))

Text("While this is on, iOS shows a VPN indicator.")
Text(String(localized: "While this is on, iOS shows a VPN indicator."))
.font(.subheadline)
.foregroundStyle(Theme.textPrimary)
.fixedSize(horizontal: false, vertical: true)
}

Text("The indicator means iOS has an active network extension. It stays visible while \(featureName) is enabled.")
Text(String(localized: "The indicator means iOS has an active network extension. It stays visible while Reticulum is running."))
.font(.caption)
.foregroundStyle(Theme.textSecondary)
.fixedSize(horizontal: false, vertical: true)
Expand All @@ -81,7 +80,7 @@ struct VPNBadgeExplainer: View {
@available(iOS 17.0, macOS 14.0, *)
@MainActor
enum VPNExplainerUI {
static func sectionHeader(icon: String, title: LocalizedStringKey) -> some View {
static func sectionHeader(icon: String, title: String) -> some View {
HStack(spacing: 8) {
Image(systemName: icon)
.font(.system(size: 16, weight: .semibold))
Expand All @@ -93,7 +92,7 @@ enum VPNExplainerUI {
}
}

static func explainerRow(icon: String, text: LocalizedStringKey) -> some View {
static func explainerRow(icon: String, text: String) -> some View {
HStack(alignment: .top, spacing: 12) {
Image(systemName: icon)
.font(.system(size: 16))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,11 @@ struct BackgroundDeliveryPage: View {
.explainerCardStyle()
}

/// "The VPN badge" note, shared with settings via `VPNBadgeExplainer`. The feature
/// name reads "background delivery" to match this flow (settings says "background
/// transport").
/// "The VPN badge" note, shared with settings via `VPNBadgeExplainer`. The
/// indicator text reads "…while Reticulum is running" (the badge is tied to
/// the in-NE Reticulum runtime on every surface).
private var badgeCard: some View {
VPNBadgeExplainer(featureName: "background delivery")
VPNBadgeExplainer()
.explainerCardStyle()
}
}
Expand Down
12 changes: 4 additions & 8 deletions Sources/ColumbaApp/Views/Settings/BackgroundTransportView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,19 +139,15 @@ struct BackgroundTransportView: View {

private var explainerCard: some View {
VStack(alignment: .leading, spacing: 12) {
VPNExplainerUI.sectionHeader(icon: "questionmark.circle", title: "What it does")
VPNExplainerUI.sectionHeader(icon: "questionmark.circle", title: String(localized: "What it does"))

VPNExplainerUI.explainerRow(
icon: "tray.and.arrow.down.fill",
text: "Receives messages, calls, and announcements even when Columba isn't open."
text: String(localized: "Receives messages, calls, and announcements even when Columba isn't open.")
)
VPNExplainerUI.explainerRow(
icon: "point.3.connected.trianglepath.dotted",
text: "Keeps your TCP and local-network (LAN) links connected to the Reticulum mesh in the background."
)
VPNExplainerUI.explainerRow(
icon: "bolt.fill",
text: "Uses more battery and data than running only in the foreground."
text: String(localized: "Keeps you connected to the Reticulum network in the background.")
)
}
.padding(16)
Expand All @@ -161,7 +157,7 @@ struct BackgroundTransportView: View {
// MARK: - Status-Bar Badge Card

private var badgeCard: some View {
VPNBadgeExplainer(featureName: "background transport")
VPNBadgeExplainer()
.padding(16)
.glassCard()
}
Expand Down
Loading
Loading