diff options
| author | Christian Cleberg <[email protected]> | 2026-04-25 00:41:34 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-04-25 00:41:34 -0500 |
| commit | 535bb0ff0f64d57be1074e33ceb42f598f80205b (patch) | |
| tree | 7e8cf8c86c226c1994555b121218484c05a5bdd4 /DomainDig/ContentView.swift | |
| parent | 1715e59287a7b48b29ed8cbf2cd45fcc92ec3126 (diff) | |
| download | domain-dig-535bb0ff0f64d57be1074e33ceb42f598f80205b.tar.gz domain-dig-535bb0ff0f64d57be1074e33ceb42f598f80205b.tar.bz2 domain-dig-535bb0ff0f64d57be1074e33ceb42f598f80205b.zip | |
DomainDig v4.1.0: Add a full local data reset flow in Data Management
- add a destructive Delete All Data action with confirmation, progress, success,
and failure handling
- centralize wipe behavior in DataResetService instead of scattering delete
logic in views
- clear local persistence, temp/export files, integration secrets,
notifications, caches, and in-memory app state
- reset sync, purchase, and integration services after wipe so the app returns
to a clean first-launch state
Polish batch and empty-state UX
- present the batch sweep summary after manual bulk searches complete, not only
from Watchlist
- align the Workflows empty state styling with other empty states by removing
the extra background card treatment
Bump the project version from 4.0.0 to 4.1.0
Diffstat (limited to 'DomainDig/ContentView.swift')
| -rw-r--r-- | DomainDig/ContentView.swift | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/DomainDig/ContentView.swift b/DomainDig/ContentView.swift index c9f40d6..c5c8e50 100644 --- a/DomainDig/ContentView.swift +++ b/DomainDig/ContentView.swift @@ -261,6 +261,9 @@ struct ContentView: View { availableDomains: viewModel.batchResults.map(\.domain) ) } + .sheet(item: manualBatchSummaryBinding) { summary in + BatchSweepSummaryView(viewModel: viewModel, summary: summary) + } .sheet(isPresented: $showingTimeline) { NavigationStack { TimelineView(viewModel: viewModel, domain: viewModel.searchedDomain) @@ -268,6 +271,19 @@ struct ContentView: View { } } + private var manualBatchSummaryBinding: Binding<BatchSweepSummary?> { + Binding( + get: { + guard let summary = viewModel.latestBatchSweepSummary, + summary.source == .manual else { + return nil + } + return summary + }, + set: { viewModel.latestBatchSweepSummary = $0 } + ) + } + private var inputSection: some View { VStack(spacing: appDensity.metrics.cardSpacing + 2) { Picker("Mode", selection: $inputMode) { @@ -3257,6 +3273,10 @@ private struct DataManagementSettingsView: View { @State private var showClearCacheConfirmation = false @State private var showClearWorkflowsConfirmation = false @State private var showClearTrackedDomainsConfirmation = false + @State private var showDeleteAllConfirmation = false + @State private var deleteAllErrorMessage: String? + @State private var deleteAllSuccessMessage: String? + @State private var isDeletingAllData = false var body: some View { Form { @@ -3277,7 +3297,28 @@ private struct DataManagementSettingsView: View { showClearTrackedDomainsConfirmation = true } } + + Section { + Button(role: .destructive) { + showDeleteAllConfirmation = true + } label: { + HStack { + Text("Delete All Data") + Spacer() + if isDeletingAllData { + ProgressView() + .controlSize(.small) + } + } + } + .disabled(isDeletingAllData) + } header: { + Text("Danger Zone") + } footer: { + Text("Permanently removes all local DomainDig data from this device.") + } } + .disabled(isDeletingAllData) .navigationTitle("Data Management") .alert("Clear history?", isPresented: $showClearHistoryConfirmation) { Button("Clear", role: .destructive) { @@ -3311,6 +3352,57 @@ private struct DataManagementSettingsView: View { } message: { Text("This removes the watchlist and clears monitoring run history. History and workflows stay intact.") } + .alert("Delete All Data?", isPresented: $showDeleteAllConfirmation) { + Button("Cancel", role: .cancel) {} + Button("Delete All Data", role: .destructive) { + deleteAllData() + } + } message: { + Text("This will permanently remove all saved DomainDig data from this device. This includes tracked domains, monitoring history, snapshots, exports, cached reports, and local settings. This action cannot be undone.") + } + .alert("Delete Failed", isPresented: Binding( + get: { deleteAllErrorMessage != nil }, + set: { if !$0 { deleteAllErrorMessage = nil } } + )) { + Button("OK", role: .cancel) {} + } message: { + Text(deleteAllErrorMessage ?? "The local data reset could not be completed.") + } + .safeAreaInset(edge: .bottom) { + if let deleteAllSuccessMessage { + Text(deleteAllSuccessMessage) + .font(.footnote.weight(.medium)) + .foregroundStyle(.secondary) + .padding(.horizontal, 14) + .padding(.vertical, 10) + .background(.thinMaterial, in: Capsule()) + .padding(.bottom, 8) + .transition(.move(edge: .bottom).combined(with: .opacity)) + } + } + } + + private func deleteAllData() { + guard !isDeletingAllData else { return } + + isDeletingAllData = true + deleteAllErrorMessage = nil + deleteAllSuccessMessage = nil + + Task { + do { + try await DataResetService.wipeAllLocalData(viewModel: viewModel) + deleteAllSuccessMessage = "All local data removed." + try? await Task.sleep(for: .seconds(2)) + if deleteAllSuccessMessage == "All local data removed." { + deleteAllSuccessMessage = nil + } + } catch { + deleteAllErrorMessage = error.localizedDescription + } + + isDeletingAllData = false + } } } |
