import SwiftUI import Supabase @MainActor class AppState: ObservableObject { @Published var isAuthenticated = false @Published var currentUser: User? @Published var windowState: WindowState = .closed private var windowTimer: Timer? enum WindowState { case closed, open, posted, missed } init() { Task { await checkSession() } startWindowTimer() observeAuthChanges() } // MARK: - Auth func checkSession() async { do { let session = try await supabase.auth.session isAuthenticated = true await loadProfile(userId: session.user.id) } catch { isAuthenticated = false } } func signIn(email: String, password: String) async throws { try await supabase.signIn(email: email, password: password) let session = try await supabase.auth.session isAuthenticated = true await loadProfile(userId: session.user.id) } func signIn(username: String, password: String) async throws { try await supabase.signIn(username: username, password: password) let session = try await supabase.auth.session isAuthenticated = true await loadProfile(userId: session.user.id) } func signUp(email: String, password: String, username: String, displayName: String) async throws { try await supabase.signUp(email: email, password: password, username: username, displayName: displayName) let session = try await supabase.auth.session isAuthenticated = true await loadProfile(userId: session.user.id) } func signOut() { Task { try? await supabase.auth.signOut() } isAuthenticated = false currentUser = nil } func deleteAccount() async throws { try await supabase.deleteAccount() isAuthenticated = false currentUser = nil } private func loadProfile(userId: UUID) async { guard let profile = try? await supabase.getMyProfile() else { return } currentUser = User( id: profile.id.uuidString, username: profile.username, displayName: profile.displayName, bio: profile.bio, avatarURL: profile.avatarUrl.flatMap(URL.init), followerCount: 0, followingCount: 0, postCount: 0, isFollowing: false ) } private func observeAuthChanges() { Task { for await (event, session) in await supabase.auth.authStateChanges { switch event { case .signedIn: if let session { isAuthenticated = true await loadProfile(userId: session.user.id) } case .signedOut, .userDeleted: isAuthenticated = false currentUser = nil default: break } } } } // MARK: - Window State func updateWindowState() { let hour = Calendar.current.component(.hour, from: Date()) guard hour >= 2 && hour < 5 else { windowState = .closed; return } let hasPosted = UserDefaults.standard.object(forKey: "lastPostDate") .flatMap { $0 as? Date } .map { Calendar.current.isDateInToday($0) } ?? false windowState = hasPosted ? .posted : .open } func markAsPosted() { UserDefaults.standard.set(Date(), forKey: "lastPostDate") updateWindowState() } private func startWindowTimer() { updateWindowState() windowTimer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { [weak self] _ in Task { @MainActor [weak self] in self?.updateWindowState() } } } }