1// GroupChatViewModel.swift
2// SophaxChat
3//
4// Observable view model for a group conversation.
5// Holds message-input and conversation state so GroupChatView stays
6// focused on layout only.
7
8import Foundation
9import Observation
10import PhotosUI
11import SophaxChatCore
12
13@MainActor
14@Observable
15final class GroupChatViewModel {
16
17 // Message input
18 var messageText: String = ""
19
20 // Message actions
21 var replyingTo: StoredMessage? = nil
22 var editingMessage: StoredMessage? = nil
23 var editingText: String = ""
24 var forwardingMessage: StoredMessage? = nil
25
26 // Search
27 var isSearching: Bool = false
28 var searchQuery: String = ""
29
30 // Attachments
31 var photoPickerItem: PhotosPickerItem? = nil
32
33 // Disappearing messages
34 var disappearingInterval: DisappearingInterval = .off
35
36 // AI sheet seed
37 var aiSeedPrompt: String? = nil
38
39 // Alert message for MLS migration result
40 var migrationAlertMessage: String = ""
41
42 private let disappearingKey: String
43 private let draftKey: String
44
45 init(group: GroupInfo) {
46 self.disappearingKey = "com.sophax.disappearingInterval.group.\(group.id)"
47 self.draftKey = "com.sophax.draft.group.\(group.id)"
48 let ud = UserDefaults.standard
49 if let raw = ud.string(forKey: disappearingKey) {
50 disappearingInterval = DisappearingInterval(rawValue: raw) ?? .off
51 }
52 messageText = ud.string(forKey: draftKey) ?? ""
53 }
54
55 func saveDraft() {
56 if messageText.isEmpty {
57 UserDefaults.standard.removeObject(forKey: draftKey)
58 } else {
59 UserDefaults.standard.set(messageText, forKey: draftKey)
60 }
61 }
62
63 func clearDraft() {
64 UserDefaults.standard.removeObject(forKey: draftKey)
65 }
66
67 func saveDisappearing() {
68 UserDefaults.standard.set(disappearingInterval.rawValue, forKey: disappearingKey)
69 }
70
71 func cancelReply() { replyingTo = nil }
72
73 func cancelEdit() {
74 editingMessage = nil
75 editingText = ""
76 }
77}