| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- import AppKit
- import SwiftUI
- import UniformTypeIdentifiers
- @MainActor
- @Observable
- final class PostGeneratorViewModel {
- var draft = PostDraft()
- var selectedTab: PostGeneratorTab = .compose
- var isGenerating = false
- var errorMessage: String?
- var successMessage: String?
- var showImageImporter = false
- private let generationService: any PostGenerationServiceProtocol
- init(generationService: any PostGenerationServiceProtocol = MockPostGenerationService()) {
- self.generationService = generationService
- }
- var formattedSubreddit: String {
- let trimmed = draft.subreddit.trimmingCharacters(in: .whitespaces)
- guard !trimmed.isEmpty else { return "r/subreddit" }
- return trimmed.hasPrefix("r/") ? trimmed : "r/\(trimmed)"
- }
- var canGenerate: Bool {
- !draft.topic.trimmingCharacters(in: .whitespaces).isEmpty
- && !draft.subreddit.trimmingCharacters(in: .whitespaces).isEmpty
- && !isGenerating
- }
- var canAddPollOption: Bool {
- draft.pollOptions.count < 6
- }
- var canRemovePollOption: Bool {
- draft.pollOptions.count > 2
- }
- func selectPostType(_ type: RedditPostType) {
- draft.postType = type
- clearMessages()
- }
- func addPollOption() {
- guard canAddPollOption else { return }
- draft.pollOptions.append(PollOption())
- }
- func removePollOption(_ option: PollOption) {
- guard canRemovePollOption else { return }
- draft.pollOptions.removeAll { $0.id == option.id }
- }
- func setImage(from url: URL) {
- draft.imageFileURL = url
- clearMessages()
- }
- func removeImage() {
- draft.imageFileURL = nil
- }
- func generatePost() async {
- guard canGenerate else { return }
- isGenerating = true
- errorMessage = nil
- successMessage = nil
- do {
- let result = try await generationService.generatePost(from: draft)
- draft.title = result.title
- if draft.postType == .text || draft.postType == .poll {
- draft.body = result.body
- }
- if let flair = result.suggestedFlair, draft.flair.isEmpty {
- draft.flair = flair
- }
- successMessage = "Post generated successfully."
- } catch {
- errorMessage = error.localizedDescription
- }
- isGenerating = false
- }
- func copyToClipboard() {
- let content = exportText()
- NSPasteboard.general.clearContents()
- NSPasteboard.general.setString(content, forType: .string)
- successMessage = "Copied to clipboard."
- errorMessage = nil
- }
- func resetDraft() {
- draft = PostDraft()
- selectedTab = .compose
- clearMessages()
- }
- func exportText() -> String {
- var lines: [String] = []
- lines.append("Subreddit: \(formattedSubreddit)")
- lines.append("Type: \(draft.postType.title)")
- if !draft.title.isEmpty {
- lines.append("Title: \(draft.title)")
- }
- switch draft.postType {
- case .text:
- if !draft.body.isEmpty { lines.append("\n\(draft.body)") }
- case .image:
- if let url = draft.imageFileURL {
- lines.append("Image: \(url.lastPathComponent)")
- }
- if !draft.body.isEmpty { lines.append("Caption: \(draft.body)") }
- case .link:
- if !draft.linkURL.isEmpty { lines.append("URL: \(draft.linkURL)") }
- if !draft.body.isEmpty { lines.append("\n\(draft.body)") }
- case .video:
- if !draft.videoURL.isEmpty { lines.append("Video URL: \(draft.videoURL)") }
- if !draft.body.isEmpty { lines.append("\n\(draft.body)") }
- case .poll:
- lines.append("Duration: \(draft.pollDuration.label)")
- for (index, option) in draft.pollOptions.enumerated() where !option.text.isEmpty {
- lines.append("Option \(index + 1): \(option.text)")
- }
- if !draft.body.isEmpty { lines.append("\n\(draft.body)") }
- }
- var tags: [String] = []
- if draft.isNSFW { tags.append("NSFW") }
- if draft.isSpoiler { tags.append("Spoiler") }
- if draft.isOC { tags.append("OC") }
- if !tags.isEmpty { lines.append("Tags: \(tags.joined(separator: ", "))") }
- if !draft.flair.isEmpty { lines.append("Flair: \(draft.flair)") }
- return lines.joined(separator: "\n")
- }
- private func clearMessages() {
- errorMessage = nil
- successMessage = nil
- }
- }
|