// // Models.swift // WatchRunner Watch App // // Created by LittleSheep on 2025/10/29. // import Foundation // MARK: - Models struct AppToken: Codable { let token: String } struct SnActivity: Codable, Identifiable { let id: String let type: String let data: ActivityData? let createdAt: Date } enum ActivityData: Codable { case post(SnPost) case discovery(DiscoveryData) case unknown init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if let post = try? container.decode(SnPost.self) { self = .post(post) return } if let discoveryData = try? container.decode(DiscoveryData.self) { self = .discovery(discoveryData) return } self = .unknown } func encode(to encoder: Encoder) throws { // Not needed for decoding } } struct SnPost: Codable, Identifiable { let id: String let title: String? let content: String? let publisher: SnPublisher let attachments: [SnCloudFile] let tags: [SnPostTag] } struct DiscoveryData: Codable { let items: [DiscoveryItem] } struct DiscoveryItem: Codable, Identifiable { var id = UUID() let type: String let data: DiscoveryItemData enum CodingKeys: String, CodingKey { case type, data } } enum DiscoveryItemData: Codable { case realm(SnRealm) case publisher(SnPublisher) case article(SnWebArticle) case unknown init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if let realm = try? container.decode(SnRealm.self) { self = .realm(realm) return } if let publisher = try? container.decode(SnPublisher.self) { self = .publisher(publisher) return } if let article = try? container.decode(SnWebArticle.self) { self = .article(article) return } self = .unknown } func encode(to encoder: Encoder) throws { // Not needed for decoding } } struct SnRealm: Codable, Identifiable { let id: String let name: String let description: String? } struct SnPublisher: Codable, Identifiable { let id: String let name: String let nick: String? let description: String? let picture: SnCloudFile? } struct SnCloudFile: Codable, Identifiable { let id: String let mimeType: String? } struct SnPostTag: Codable, Identifiable { let id: String let slug: String let name: String? } struct SnWebArticle: Codable, Identifiable { let id: String let title: String let url: String } struct SnNotification: Codable, Identifiable { let id: String let topic: String let title: String let subtitle: String let content: String let meta: [String: AnyCodable]? let priority: Int let viewedAt: Date? let accountId: String let createdAt: Date let updatedAt: Date let deletedAt: Date? enum CodingKeys: String, CodingKey { case id case topic case title case subtitle case content case meta case priority case viewedAt = "viewedAt" case accountId = "accountId" case createdAt = "createdAt" case updatedAt = "updatedAt" case deletedAt = "deletedAt" } } struct AnyCodable: Codable { let value: Any init(_ value: Any) { self.value = value } init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if let intValue = try? container.decode(Int.self) { value = intValue } else if let doubleValue = try? container.decode(Double.self) { value = doubleValue } else if let boolValue = try? container.decode(Bool.self) { value = boolValue } else if let stringValue = try? container.decode(String.self) { value = stringValue } else if let arrayValue = try? container.decode([AnyCodable].self) { value = arrayValue } else if let dictValue = try? container.decode([String: AnyCodable].self) { value = dictValue } else { value = NSNull() } } func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch value { case let intValue as Int: try container.encode(intValue) case let doubleValue as Double: try container.encode(doubleValue) case let boolValue as Bool: try container.encode(boolValue) case let stringValue as String: try container.encode(stringValue) case let arrayValue as [AnyCodable]: try container.encode(arrayValue) case let dictValue as [String: AnyCodable]: try container.encode(dictValue) default: try container.encodeNil() } } } struct NotificationResponse { let notifications: [SnNotification] let total: Int let hasMore: Bool } struct ActivityResponse { let activities: [SnActivity] let hasMore: Bool let nextCursor: String? } struct SnAccount: Codable { let id: String let name: String let nick: String let profile: SnUserProfile let createdAt: Date } struct SnUserProfile: Codable { let bio: String? let picture: SnCloudFile? let background: SnCloudFile? let level: Int let experience: Int let levelingProgress: Double } struct SnAccountStatus: Codable { let id: String let attitude: Int let isOnline: Bool let isInvisible: Bool let isNotDisturb: Bool let isCustomized: Bool let label: String let meta: [String: AnyCodable]? let clearedAt: Date? let accountId: String let createdAt: Date let updatedAt: Date let deletedAt: Date? }