From 9d61167e810f3318dadbb4da160396fe37ef8f94 Mon Sep 17 00:00:00 2001 From: Wilhelm Oks Date: Fri, 13 Dec 2024 12:35:30 +0100 Subject: [PATCH] Models WIP: Profile --- Sources/SwiftDevRant/Models/Comment.swift | 2 +- .../Models/Profile.Content.Elements.swift | 48 +++++++ .../Models/Profile.Content.Numbers.swift | 48 +++++++ .../SwiftDevRant/Models/Profile.Content.swift | 27 ++++ Sources/SwiftDevRant/Models/Profile.swift | 119 ++++++++++++++++++ Sources/SwiftDevRant/Models/Rant.swift | 2 +- Sources/SwiftDevRant/Models/User.swift | 7 +- 7 files changed, 248 insertions(+), 5 deletions(-) create mode 100644 Sources/SwiftDevRant/Models/Profile.Content.Elements.swift create mode 100644 Sources/SwiftDevRant/Models/Profile.Content.Numbers.swift create mode 100644 Sources/SwiftDevRant/Models/Profile.Content.swift create mode 100644 Sources/SwiftDevRant/Models/Profile.swift diff --git a/Sources/SwiftDevRant/Models/Comment.swift b/Sources/SwiftDevRant/Models/Comment.swift index 7f46e2b..5aa743f 100644 --- a/Sources/SwiftDevRant/Models/Comment.swift +++ b/Sources/SwiftDevRant/Models/Comment.swift @@ -78,7 +78,7 @@ extension Comment.CodingData { name: user_username, score: user_score, devRantSupporter: (user_dpp ?? 0) != 0, - avatar: user_avatar.decoded, + avatarSmall: user_avatar.decoded, avatarLarge: user_avatar_lg?.decoded ), created: Date(timeIntervalSince1970: TimeInterval(created_time)), diff --git a/Sources/SwiftDevRant/Models/Profile.Content.Elements.swift b/Sources/SwiftDevRant/Models/Profile.Content.Elements.swift new file mode 100644 index 0000000..1919870 --- /dev/null +++ b/Sources/SwiftDevRant/Models/Profile.Content.Elements.swift @@ -0,0 +1,48 @@ +public extension Profile.Content { + struct Elements: Hashable { + /// The rants that the user has created. + public let rants: [Rant] + + /// The rants that the user has upvoted. + public let upvotedRants: [Rant] + + /// The comments that the user has created. + public let comments: [Comment] + + /// The rants that the user has marked as favorite. + public let favorites: [Rant] + + /// If the profile is from the logged in user, then this list contains rants that user has viewed in the past. + public let viewed: [Rant] + + public init(rants: [Rant], upvotedRants: [Rant], comments: [Comment], favorites: [Rant], viewed: [Rant]) { + self.rants = rants + self.upvotedRants = upvotedRants + self.comments = comments + self.favorites = favorites + self.viewed = viewed + } + } +} + +extension Profile.Content.Elements { + struct CodingData: Codable { + let rants: [Rant.CodingData] + let upvoted: [Rant.CodingData] + let comments: [Comment.CodingData] + let favorites: [Rant.CodingData]? + let viewed: [Rant.CodingData]? + } +} + +extension Profile.Content.Elements.CodingData { + var decoded: Profile.Content.Elements { + .init( + rants: rants.map(\.decoded), + upvotedRants: upvoted.map(\.decoded), + comments: comments.map(\.decoded), + favorites: favorites?.map(\.decoded) ?? [], + viewed: viewed?.map(\.decoded) ?? [] + ) + } +} diff --git a/Sources/SwiftDevRant/Models/Profile.Content.Numbers.swift b/Sources/SwiftDevRant/Models/Profile.Content.Numbers.swift new file mode 100644 index 0000000..40f8735 --- /dev/null +++ b/Sources/SwiftDevRant/Models/Profile.Content.Numbers.swift @@ -0,0 +1,48 @@ +public extension Profile.Content { + struct Numbers: Hashable { + /// The number of rants that the user has created. + public let rants: Int + + /// The number of rants that the user has upvoted. + public let upvotedRants: Int + + /// The number of the comments that the user has created. + public let comments: Int + + /// The number of rants that the user has marked as favorite. + public let favorites: Int + + /// The number of collaborations the user has created. + public let collaborations: Int + + public init(rants: Int, upvotedRants: Int, comments: Int, favorites: Int, collaborations: Int) { + self.rants = rants + self.upvotedRants = upvotedRants + self.comments = comments + self.favorites = favorites + self.collaborations = collaborations + } + } +} + +extension Profile.Content.Numbers { + struct CodingData: Codable { + let rants: Int + let upvoted: Int + let comments: Int + let favorites: Int + let collabs: Int + } +} + +extension Profile.Content.Numbers.CodingData { + var decoded: Profile.Content.Numbers { + .init( + rants: rants, + upvotedRants: upvoted, + comments: comments, + favorites: favorites, + collaborations: collabs + ) + } +} diff --git a/Sources/SwiftDevRant/Models/Profile.Content.swift b/Sources/SwiftDevRant/Models/Profile.Content.swift new file mode 100644 index 0000000..2e32599 --- /dev/null +++ b/Sources/SwiftDevRant/Models/Profile.Content.swift @@ -0,0 +1,27 @@ +public extension Profile { + struct Content: Hashable { + public let elements: Elements + public let numbers: Numbers + + public init(elements: Profile.Content.Elements, numbers: Profile.Content.Numbers) { + self.elements = elements + self.numbers = numbers + } + } +} + +extension Profile.Content { + struct CodingData: Codable { + let content: Elements.CodingData + let counts: Numbers.CodingData + } +} + +extension Profile.Content.CodingData { + var decoded: Profile.Content { + .init( + elements: content.decoded, + numbers: counts.decoded + ) + } +} diff --git a/Sources/SwiftDevRant/Models/Profile.swift b/Sources/SwiftDevRant/Models/Profile.swift new file mode 100644 index 0000000..43973ca --- /dev/null +++ b/Sources/SwiftDevRant/Models/Profile.swift @@ -0,0 +1,119 @@ +import Foundation + +/// Holds information, content and the activity history of a user. +public struct Profile: Hashable { + /// The user's alias. + public let username: String + + /// The number of upvotes that the user got from other users. + public let score: Int + + /// The time when the user created the account. + public let created: Date + + /// The description of the user. + public let about: String? + + /// The description of the geographic location. + public let location: String? + + /// The description of the user's skills. + public let skills: String? + + /// The user's GitHub reference. + public let github: String? + + /// The user's personal website. + public let website: String? + + /// The user's content and activities. + public let content: Content + + /// The user's large avatar, for profile views. + public let avatarLarge: User.Avatar + + /// The user's small avatar, for rant views and comment views. + public let avatarSmall: User.Avatar + + /// True if the user is subscribed to devRant++. + public let devRantSupporter: Bool + + /// True if the logged in user is subscribed to the user of this profile. + public let subscribed: Bool //TODO: where is this set? It's not in the json data of the profile + + public init(username: String, score: Int, created: Date, about: String?, location: String?, skills: String?, github: String?, website: String?, content: Profile.Content, avatarLarge: User.Avatar, avatarSmall: User.Avatar, devRantSupporter: Bool, subscribed: Bool) { + self.username = username + self.score = score + self.created = created + self.about = about + self.location = location + self.skills = skills + self.github = github + self.website = website + self.content = content + self.avatarLarge = avatarLarge + self.avatarSmall = avatarSmall + self.devRantSupporter = devRantSupporter + self.subscribed = subscribed + } +} + +public extension Profile { + enum ContentType: String { + /// All user content. + case all = "all" + + /// The user's rants. + case rants = "rants" + + /// The user's comments. + case comments = "comments" + + /// Rants or comments upvoted by the user. + case upvoted = "upvoted" + + /// The user's favorite rants. + case favorite = "favorites" + + /// The rants viewd by the user. + case viewed = "viewed" + } +} + +extension Profile { + struct CodingData: Codable { + let username: String + let score: Int + let created_time: Int + let about: String + let location: String + let skills: String + let github: String + let website: String + let content: Content.CodingData + let avatar: User.Avatar.CodingData + let avatar_sm: User.Avatar.CodingData + let dpp: Int? + let subscribed: Bool? //TODO: check if it exists in the json data + } +} + +extension Profile.CodingData { + var decoded: Profile { + .init( + username: username, + score: score, + created: Date(timeIntervalSince1970: TimeInterval(created_time)), + about: about.isEmpty ? nil : about, + location: location.isEmpty ? nil : location, + skills: skills.isEmpty ? nil : skills, + github: github.isEmpty ? nil : github, + website: website.isEmpty ? nil : website, + content: content.decoded, + avatarLarge: avatar.decoded, + avatarSmall: avatar_sm.decoded, + devRantSupporter: (dpp ?? 0) != 0, + subscribed: subscribed ?? false + ) + } +} diff --git a/Sources/SwiftDevRant/Models/Rant.swift b/Sources/SwiftDevRant/Models/Rant.swift index 7b9118a..a8ec118 100644 --- a/Sources/SwiftDevRant/Models/Rant.swift +++ b/Sources/SwiftDevRant/Models/Rant.swift @@ -107,7 +107,7 @@ extension Rant.CodingData { name: user_username, score: user_score, devRantSupporter: (user_dpp ?? 0) != 0, - avatar: user_avatar.decoded, + avatarSmall: user_avatar.decoded, avatarLarge: user_avatar_lg.decoded ), created: Date(timeIntervalSince1970: TimeInterval(created_time)), diff --git a/Sources/SwiftDevRant/Models/User.swift b/Sources/SwiftDevRant/Models/User.swift index 97f0d41..a6344f8 100644 --- a/Sources/SwiftDevRant/Models/User.swift +++ b/Sources/SwiftDevRant/Models/User.swift @@ -1,3 +1,4 @@ +/// Represents a user. public struct User: Identifiable, Hashable { public let id: Int @@ -10,17 +11,17 @@ public struct User: Identifiable, Hashable { public let devRantSupporter: Bool /// A small avatar for the rant views and comment views. - public let avatar: Avatar + public let avatarSmall: Avatar /// A large avatar for the profile view. public let avatarLarge: Avatar? - public init(id: Int, name: String, score: Int, devRantSupporter: Bool, avatar: User.Avatar, avatarLarge: User.Avatar?) { + public init(id: Int, name: String, score: Int, devRantSupporter: Bool, avatarSmall: User.Avatar, avatarLarge: User.Avatar?) { self.id = id self.name = name self.score = score self.devRantSupporter = devRantSupporter - self.avatar = avatar + self.avatarSmall = avatarSmall self.avatarLarge = avatarLarge } }