| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- import AppKit
- import Combine
- import Foundation
- @MainActor
- final class EmailWriterViewModel: ObservableObject {
- static let maxWords = 5_000
- @Published var subject: String = ""
- @Published var prompt: String = ""
- @Published var generatedEmail: String = ""
- @Published var emailType: EmailType = .followUp
- @Published var tone: EmailTone = .professional
- @Published private(set) var isGenerating = false
- @Published private(set) var errorMessage: String?
- private let emailWriterService: any EmailWriterServicing
- private let historyStorage: HistoryStoring
- init(
- emailWriterService: any EmailWriterServicing = EmailWriterService(),
- historyStorage: HistoryStoring = HistoryStorageService.shared
- ) {
- self.emailWriterService = emailWriterService
- self.historyStorage = historyStorage
- }
- var wordCountLimitLabel: String {
- "\(prompt.wordCount)/\(Self.maxWords)"
- }
- var canGenerate: Bool {
- !prompt.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && !isGenerating
- }
- var canCopy: Bool {
- !generatedEmail.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
- }
- func pastePrompt() {
- guard let clipboard = NSPasteboard.general.string(forType: .string) else { return }
- prompt = clipboard.truncated(toMaxWords: Self.maxWords)
- generatedEmail = ""
- errorMessage = nil
- }
- func clearAll() {
- subject = ""
- prompt = ""
- generatedEmail = ""
- errorMessage = nil
- }
- func copyGeneratedEmail() {
- guard canCopy else { return }
- NSPasteboard.general.clearContents()
- NSPasteboard.general.setString(generatedEmail, forType: .string)
- }
- func generateEmail() {
- let trimmedPrompt = prompt.trimmingCharacters(in: .whitespacesAndNewlines)
- guard !trimmedPrompt.isEmpty else { return }
- isGenerating = true
- generatedEmail = ""
- errorMessage = nil
- let subjectLine = subject.trimmingCharacters(in: .whitespacesAndNewlines)
- Task {
- do {
- let email = try await emailWriterService.generateEmail(
- prompt: trimmedPrompt,
- subject: subjectLine,
- emailType: emailType,
- tone: tone
- )
- generatedEmail = email
- saveToHistory(
- subject: subjectLine,
- prompt: trimmedPrompt,
- generatedEmail: email
- )
- } catch {
- errorMessage = error.localizedDescription
- }
- isGenerating = false
- }
- }
- func restore(from entry: HistoryEntry) {
- guard case .emailWriter(let data) = entry.payload else { return }
- subject = data.subject
- prompt = data.prompt
- generatedEmail = data.generatedEmail
- emailType = data.emailType
- tone = data.tone
- errorMessage = nil
- }
- private func saveToHistory(subject: String, prompt: String, generatedEmail: String) {
- let payload = HistoryPayload.emailWriter(
- EmailWriterHistoryData(
- subject: subject,
- prompt: prompt,
- generatedEmail: generatedEmail,
- emailType: emailType,
- tone: tone
- )
- )
- let titleSource = subject.isEmpty ? prompt : subject
- let entry = HistoryEntry(
- tool: .aiEmailWriter,
- title: HistoryHelpers.title(from: titleSource, fallback: "Generated Email"),
- preview: HistoryHelpers.preview(from: generatedEmail),
- payload: payload
- )
- historyStorage.save(entry)
- }
- }
|