233 lines
5.5 KiB
Swift
233 lines
5.5 KiB
Swift
//
|
|
// 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
|
|
}
|