Files
damus/damus/Features/Settings/Views/PrivacySettingsView.swift
T
Daniel D’Aquino 3c98282f95 Sentry integration
Changelog-Added: Added Sentry error and diagnostics reporting to aid
future quality improvements
Closes: #3731
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2026-05-11 11:30:20 -07:00

166 lines
7.8 KiB
Swift

//
// PrivacySettingsView.swift
// damus
//
// Created for privacy and data collection settings
//
import Foundation
import SwiftUI
import Sentry
struct PrivacySettingsView: View {
@ObservedObject var globalSettings = GlobalSettingsStore.shared
@State private var isShowingPrivacyDetails = false
var body: some View {
Form {
Section(
header: Text("Error & Diagnostics Reporting", comment: "Section header for error and diagnostics reporting settings"),
footer: VStack(alignment: .leading, spacing: 8) {
Text("Sentry provides reporting for crashes, errors, and app health issues. When enabled, anonymous technical data is sent to help improve the app. No personal information or private keys are collected. This setting applies to the entire app on this device and is not tied to a specific account. Restart the app for changes to take effect.", comment: "Footer explaining Sentry telemetry")
Button(NSLocalizedString("Learn more", comment: "Button title to show more details about privacy and data handling")) {
isShowingPrivacyDetails = true
}
.font(.footnote)
}
) {
Toggle(NSLocalizedString("Enable Error & Diagnostics Reporting", comment: "Setting to enable Sentry error and diagnostics reporting"), isOn: $globalSettings.enable_sentry_telemetry)
.toggleStyle(.switch)
}
}
.navigationTitle(NSLocalizedString("Privacy", comment: "Navigation title for Privacy settings"))
.sheet(isPresented: $isShowingPrivacyDetails) {
PrivacyDataHandlingDetailsView()
}
}
}
/// Presents additional context about diagnostics reporting and the data shared with Sentry.
struct PrivacyDataHandlingDetailsView: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationStack {
List {
Section {
Text("When diagnostics reporting is enabled, Damus sends anonymous technical information to Sentry so crashes, errors, and app stability problems can be investigated and fixed faster.", comment: "Overview of diagnostics reporting and why it exists")
} header: {
Text("How it works", comment: "Section title describing how diagnostics reporting works")
}
Section {
PrivacyInfoRow(
icon: "chart.bar.xaxis",
title: NSLocalizedString("What is shared", comment: "Title for information about data that is shared"),
description: NSLocalizedString("Crash reports, error messages, app version, iOS version, device model, and basic performance diagnostics.", comment: "Description of shared diagnostics data")
)
PrivacyInfoRow(
icon: "hand.raised.fill",
title: NSLocalizedString("What is not shared", comment: "Title for information about data that is not shared"),
description: NSLocalizedString("Private keys, seed phrases, wallet secrets, direct message contents, and profile content you create in the app.", comment: "Description of private data that is not shared")
)
PrivacyInfoRow(
icon: "switch.2",
title: NSLocalizedString("Your control", comment: "Title for information about user control over diagnostics reporting"),
description: NSLocalizedString("You can turn diagnostics reporting on or off at any time from Privacy settings. Changes apply after restarting the app. Turning it off stops future reports from being sent, but does not delete reports that were already sent.", comment: "Description of user control over diagnostics reporting")
)
} header: {
Text("Data handling details", comment: "Section title for detailed data handling information")
}
Section {
CollectedDataRow(
title: NSLocalizedString("Crash and exception details", comment: "Title for crash and exception details row"),
description: NSLocalizedString("Technical stack traces and failure context used to debug app issues.", comment: "Description for crash and exception details row"),
collected: true
)
CollectedDataRow(
title: NSLocalizedString("Device and app metadata", comment: "Title for device and app metadata row"),
description: NSLocalizedString("Information such as app version, operating system version, and device type.", comment: "Description for device and app metadata row"),
collected: true
)
CollectedDataRow(
title: NSLocalizedString("Messages, notes, and private keys", comment: "Title for sensitive data row"),
description: NSLocalizedString("Personal content and credentials are not intentionally collected for diagnostics reporting. Damus is designed not to send sensitive information such as private keys, public keys, or email addresses, and it also automatically detects and redacts those patterns as an additional safeguard before reports are sent.", comment: "Description for sensitive data row"),
collected: false
)
} header: {
Text("Collected data summary", comment: "Section title summarizing collected data")
}
}
.navigationTitle(NSLocalizedString("Diagnostics Privacy", comment: "Navigation title for the privacy details sheet"))
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button(NSLocalizedString("Done", comment: "Button to dismiss privacy details sheet")) {
dismiss()
}
}
}
}
}
}
// MARK: - Supporting Views
struct PrivacyInfoRow: View {
let icon: String
let title: String
let description: String
var body: some View {
HStack(spacing: 12) {
Image(systemName: icon)
.foregroundColor(.green)
.font(.system(size: 20))
.frame(width: 24)
VStack(alignment: .leading, spacing: 2) {
Text(title)
.font(.subheadline)
.fontWeight(.semibold)
Text(description)
.font(.caption)
.foregroundColor(.secondary)
}
}
}
}
struct CollectedDataRow: View {
let title: String
let description: String
let collected: Bool
var body: some View {
HStack(spacing: 12) {
Image(systemName: collected ? "checkmark.circle.fill" : "xmark.circle.fill")
.foregroundColor(collected ? .blue : .gray)
.font(.system(size: 20))
.frame(width: 24)
VStack(alignment: .leading, spacing: 2) {
Text(title)
.font(.subheadline)
.fontWeight(.semibold)
Text(description)
.font(.caption)
.foregroundColor(.secondary)
}
}
}
}
// MARK: - Preview
struct PrivacySettingsView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
PrivacySettingsView()
}
}
}