vOOice/VoiceInk/Views/Settings/AudioCleanupSettingsView.swift
2025-08-07 01:18:35 +05:45

164 lines
7.8 KiB
Swift

import SwiftUI
import SwiftData
/// A view component for configuring audio cleanup settings
struct AudioCleanupSettingsView: View {
@EnvironmentObject private var whisperState: WhisperState
// Audio cleanup settings
@AppStorage("DoNotMaintainTranscriptHistory") private var doNotMaintainTranscriptHistory = false
@AppStorage("IsAudioCleanupEnabled") private var isAudioCleanupEnabled = true
@AppStorage("AudioRetentionPeriod") private var audioRetentionPeriod = 7
@State private var isPerformingCleanup = false
@State private var isShowingConfirmation = false
@State private var cleanupInfo: (fileCount: Int, totalSize: Int64, transcriptions: [Transcription]) = (0, 0, [])
@State private var showResultAlert = false
@State private var cleanupResult: (deletedCount: Int, errorCount: Int) = (0, 0)
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Text("Control how VoiceInk handles your transcription data and audio recordings for privacy and storage management.")
.font(.system(size: 13))
.foregroundColor(.secondary)
.fixedSize(horizontal: false, vertical: true)
Text("Data Retention")
.font(.system(size: 14, weight: .semibold))
.foregroundColor(.primary)
.padding(.top, 8)
Toggle("Do not maintain transcript history", isOn: $doNotMaintainTranscriptHistory)
.toggleStyle(.switch)
.padding(.vertical, 4)
if doNotMaintainTranscriptHistory {
Text("When enabled, no transcription history will be saved. This provides zero data retention for maximum privacy.")
.font(.system(size: 13))
.foregroundColor(.orange)
.fixedSize(horizontal: false, vertical: true)
.padding(.top, 2)
}
if !doNotMaintainTranscriptHistory {
Divider()
.padding(.vertical, 8)
Text("Audio File Management")
.font(.system(size: 14, weight: .semibold))
.foregroundColor(.primary)
Text("Automatically delete audio files from transcription history while preserving the text transcripts.")
.font(.system(size: 13))
.foregroundColor(.secondary)
.fixedSize(horizontal: false, vertical: true)
Toggle("Enable automatic audio cleanup", isOn: $isAudioCleanupEnabled)
.toggleStyle(.switch)
.padding(.vertical, 4)
}
if isAudioCleanupEnabled && !doNotMaintainTranscriptHistory {
VStack(alignment: .leading, spacing: 8) {
Text("Retention Period")
.font(.system(size: 14, weight: .medium))
Picker("Keep audio files for", selection: $audioRetentionPeriod) {
Text("1 day").tag(1)
Text("3 days").tag(3)
Text("7 days").tag(7)
Text("14 days").tag(14)
Text("30 days").tag(30)
}
.pickerStyle(.menu)
Text("Audio files older than the selected period will be automatically deleted, while keeping the text transcripts intact.")
.font(.system(size: 13))
.foregroundColor(.secondary)
.fixedSize(horizontal: false, vertical: true)
.padding(.top, 2)
}
.padding(.vertical, 4)
Button(action: {
// Start by analyzing what would be cleaned up
Task {
// Update UI state
await MainActor.run {
isPerformingCleanup = true
}
// Get cleanup info
let info = await AudioCleanupManager.shared.getCleanupInfo(modelContext: whisperState.modelContext)
// Update UI with results
await MainActor.run {
cleanupInfo = info
isPerformingCleanup = false
isShowingConfirmation = true
}
}
}) {
HStack {
if isPerformingCleanup {
ProgressView()
.controlSize(.small)
.padding(.trailing, 4)
} else {
Image(systemName: "arrow.clockwise")
}
Text(isPerformingCleanup ? "Analyzing..." : "Run Cleanup Now")
}
}
.buttonStyle(.bordered)
.controlSize(.large)
.disabled(isPerformingCleanup)
.alert("Audio Cleanup", isPresented: $isShowingConfirmation) {
Button("Cancel", role: .cancel) { }
if cleanupInfo.fileCount > 0 {
Button("Delete \(cleanupInfo.fileCount) Files", role: .destructive) {
Task {
// Update UI state
await MainActor.run {
isPerformingCleanup = true
}
// Perform cleanup
let result = await AudioCleanupManager.shared.runCleanupForTranscriptions(
modelContext: whisperState.modelContext,
transcriptions: cleanupInfo.transcriptions
)
// Update UI with results
await MainActor.run {
cleanupResult = result
isPerformingCleanup = false
showResultAlert = true
}
}
}
}
} message: {
VStack(alignment: .leading, spacing: 8) {
if cleanupInfo.fileCount > 0 {
Text("This will delete \(cleanupInfo.fileCount) audio files older than \(audioRetentionPeriod) day\(audioRetentionPeriod > 1 ? "s" : "").")
Text("Total size to be freed: \(AudioCleanupManager.shared.formatFileSize(cleanupInfo.totalSize))")
Text("The text transcripts will be preserved.")
} else {
Text("No audio files found that are older than \(audioRetentionPeriod) day\(audioRetentionPeriod > 1 ? "s" : "").")
}
}
}
.alert("Cleanup Complete", isPresented: $showResultAlert) {
Button("OK", role: .cancel) { }
} message: {
if cleanupResult.errorCount > 0 {
Text("Successfully deleted \(cleanupResult.deletedCount) audio files. Failed to delete \(cleanupResult.errorCount) files.")
} else {
Text("Successfully deleted \(cleanupResult.deletedCount) audio files.")
}
}
}
}
}
}