|
"source": "import Foundation\n\npublic struct Rant: Identifiable, Hashable, Sendable {\n /// The id of this rant.\n public let id: Int\n \n /// A URL link to this rant.\n public let linkToRant: String?\n \n /// The current logged in user's vote on this rant.\n public let voteState: VoteState\n \n /// The number of upvotes from other users.\n public let score: Int\n \n /// The user who wrote this rant.\n public let author: User\n \n /// The time when this rant was created.\n public let created: Date\n \n /// True if this rant is edited by the author.\n public let isEdited: Bool\n \n /// True if this rant has been marked as a favorite by the logged in user.\n public var isFavorite: Bool\n \n /// The text contents of this rant.\n public let text: String\n \n /// The URLs and user mentions inside of the text of this rant.\n public let linksInText: [Link]\n \n /// The optional image that the user has uploaded for this rant.\n public let image: AttachedImage?\n \n /// The number of comments that this rant has.\n public let numberOfComments: Int\n \n /// The tags for this rant.\n public let tags: [String]\n \n /// Holds information about the weekly topic if this rant is of type weekly.\n public let weekly: Weekly?\n \n /// Holds information about the collaboration project if this rant is of type collaboration.\n public let collaboration: Collaboration?\n \n public init(id: Int, linkToRant: String?, voteState: VoteState, score: Int, author: User, created: Date, isEdited: Bool, isFavorite: Bool, text: String, linksInText: [Link], image: AttachedImage?, numberOfComments: Int, tags: [String], weekly: Rant.Weekly?, collaboration: Collaboration?) {\n self.id = id\n self.linkToRant = linkToRant\n self.voteState = voteState\n self.score = score\n self.author = author\n self.created = created\n self.isEdited = isEdited\n self.isFavorite = isFavorite\n self.text = text\n self.linksInText = linksInText\n self.image = image\n self.numberOfComments = numberOfComments\n self.tags = tags\n self.weekly = weekly\n self.collaboration = collaboration\n }\n}\n\nextension Rant {\n struct CodingData: Codable {\n let id: Int\n let text: String\n let score: Int\n let created_time: Int\n let attached_image: AttachedImage.CodingData? // this value can also be of type String. See the custom decoding code.\n let num_comments: Int\n let tags: [String]\n let vote_state: Int\n let edited: Bool\n let favorited: Int?\n let link: String?\n let links: [Link.CodingData]?\n let weekly: Weekly.CodingData?\n let c_type: Int?\n let c_type_long: String?\n let c_description: String?\n let c_tech_stack: String?\n let c_team_size: String?\n let c_url: String?\n let user_id: Int\n let user_username: String\n let user_score: Int\n let user_avatar: User.Avatar.CodingData\n let user_avatar_lg: User.Avatar.CodingData\n let user_dpp: Int?\n \n init(from decoder: Decoder) throws {\n // We need custom decoding code here because the attached_image can be a dictionary OR a string.\n \n let values = try decoder.container(keyedBy: CodingKeys.self)\n \n id = try values.decode(Int.self, forKey: .id)\n text = try values.decode(String.self, forKey: .text)\n score = try values.decode(Int.self, forKey: .score)\n created_time = try values.decode(Int.self, forKey: .created_time)\n \n do {\n // If the value is an object, decode it into an attached image.\n attached_image = try values.decode(AttachedImage.CodingData.self, forKey: .attached_image)\n } catch {\n // Otherwise it was an empty string. Treat is as no attached image.\n attached_image = nil\n }\n \n num_comments = try values.decode(Int.self, forKey: .num_comments)\n tags = try values.decode([String].self, forKey: .tags)\n vote_state = try values.decode(Int.self, forKey: .vote_state)\n weekly = try? values.decode(Weekly.CodingData.self, forKey: .weekly)\n edited = try values.decode(Bool.self, forKey: .edited)\n favorited = try? values.decode(Int.self, forKey: .favorited)\n link = try? values.decode(String.self, forKey: .link)\n links = try? values.decode([Link.CodingData].self, forKey: .links)\n \n c_type = try? values.decode(Int.self, forKey: .c_type)\n c_type_long = try? values.decode(String.self, forKey: .c_type_long)\n c_description = try? values.decode(String.self, forKey: .c_description)\n c_tech_stack = try? values.decode(String.self, forKey: .c_tech_stack)\n c_team_size = try? values.decode(String.self, forKey: .c_team_size)\n c_url = try? values.decode(String.self, forKey: .c_url)\n \n user_id = try values.decode(Int.self, forKey: .user_id)\n user_username = try values.decode(String.self, forKey: .user_username)\n user_score = try values.decode(Int.self, forKey: .user_score)\n user_avatar = try values.decode(User.Avatar.CodingData.self, forKey: .user_avatar)\n user_avatar_lg = try values.decode(User.Avatar.CodingData.self, forKey: .user_avatar_lg)\n user_dpp = try? values.decode(Int.self, forKey: .user_dpp)\n }\n }\n}\n\nextension Rant.CodingData {\n var decoded: Rant {\n .init(\n id: id,\n linkToRant: link,\n voteState: .init(rawValue: vote_state) ?? .unvoted,\n score: score,\n author: .init(\n id: user_id,\n name: user_username,\n score: user_score,\n devRantSupporter: (user_dpp ?? 0) != 0,\n avatarSmall: user_avatar.decoded,\n avatarLarge: user_avatar_lg.decoded\n ),\n created: Date(timeIntervalSince1970: TimeInterval(created_time)),\n isEdited: edited,\n isFavorite: (favorited ?? 0) != 0,\n text: text,\n linksInText: links?.map(\\.decoded) ?? [],\n image: attached_image?.decoded,\n numberOfComments: num_comments,\n tags: tags,\n weekly: weekly?.decoded,\n collaboration: decodedCollaboration\n )\n }\n \n private var decodedCollaboration: Collaboration? {\n guard c_type != nil || c_type_long != nil || c_description != nil || c_tech_stack != nil || c_team_size != nil || c_url != nil else {\n return nil\n }\n return .init(\n kind: c_type.flatMap { .init(rawValue: $0) },\n kindDescription: c_type_long ?? \"\",\n description: c_description ?? \"\",\n techStack: c_tech_stack ?? \"\",\n teamSize: c_team_size ?? \"\",\n url: c_url ?? \"\"\n )\n }\n}\n",
|