Models WIP: Notification, NotificationFeed
This commit is contained in:
parent
fc331b32c3
commit
394e9a92c3
86
Sources/SwiftDevRant/Models/Notification.swift
Normal file
86
Sources/SwiftDevRant/Models/Notification.swift
Normal file
@ -0,0 +1,86 @@
|
||||
import Foundation
|
||||
|
||||
/// A notification about activities in a rant or a comment.
|
||||
public struct Notification: Hashable, Identifiable {
|
||||
public enum Kind: String {
|
||||
/// An upvote for a rant.
|
||||
case rantUpvote = "content_vote"
|
||||
|
||||
/// An upvote for a comment.
|
||||
case commentUpvote = "comment_vote"
|
||||
|
||||
/// A new comment in one of the logged in user's rants.
|
||||
case newCommentInOwnRant = "comment_content"
|
||||
|
||||
/// A new comment in a rant that the logged in user has commented in.
|
||||
case newComment = "comment_discuss"
|
||||
|
||||
/// A mention of the logged in user in a comment.
|
||||
case mentionInComment = "comment_mention"
|
||||
|
||||
/// A new rant posted by someone that the logged in user is subscribed to.
|
||||
case newRantOfSubscribedUser = "rant_sub"
|
||||
}
|
||||
|
||||
/// The id of the rant associated with this notification.
|
||||
public let rantId: Int
|
||||
|
||||
/// The id of the comment associated with this notification, if this notification is for a comment.
|
||||
public let commentId: Int?
|
||||
|
||||
/// The time when this notification was created.
|
||||
public let created: Date
|
||||
|
||||
/// True if the user has already read this notification.
|
||||
public let read: Bool
|
||||
|
||||
/// The type of this notification.
|
||||
public let kind: Kind
|
||||
|
||||
/// The id of the user who triggered the notification.
|
||||
public let userId: Int
|
||||
|
||||
public var id: String {
|
||||
[
|
||||
String(rantId),
|
||||
commentId.flatMap{ String($0) } ?? "-",
|
||||
String(Int(created.timeIntervalSince1970)),
|
||||
String(read),
|
||||
kind.rawValue,
|
||||
String(userId)
|
||||
].joined(separator: "|")
|
||||
}
|
||||
|
||||
public init(rantId: Int, commentId: Int?, created: Date, read: Bool, kind: Notification.Kind, userId: Int) {
|
||||
self.rantId = rantId
|
||||
self.commentId = commentId
|
||||
self.created = created
|
||||
self.read = read
|
||||
self.kind = kind
|
||||
self.userId = userId
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification {
|
||||
struct CodingData: Codable {
|
||||
let rant_id: Int
|
||||
let comment_id: Int?
|
||||
let created_time: Int
|
||||
let read: Int
|
||||
let type: String
|
||||
let uid: Int
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.CodingData {
|
||||
var decoded: Notification {
|
||||
.init(
|
||||
rantId: rant_id,
|
||||
commentId: comment_id,
|
||||
created: Date(timeIntervalSince1970: TimeInterval(created_time)),
|
||||
read: read != 0,
|
||||
kind: .init(rawValue: type) ?? .newComment,
|
||||
userId: uid
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
public extension NotificationFeed {
|
||||
/// Holds numbers of unread notifications for each type of notification.
|
||||
struct UnreadNumbers: Decodable, Hashable {
|
||||
/// The total number of unread notifications
|
||||
public let all: Int
|
||||
|
||||
/// The number of unread commets.
|
||||
public let comments: Int
|
||||
|
||||
/// The number of unread mentions.
|
||||
public let mentions: Int
|
||||
|
||||
/// The number of unread rants from users which the logged in user is subscribed to.
|
||||
public let subscriptions: Int
|
||||
|
||||
/// The number of unread upvotes.
|
||||
public let upvotes: Int
|
||||
|
||||
public init(all: Int, comments: Int, mentions: Int, subscriptions: Int, upvotes: Int) {
|
||||
self.all = all
|
||||
self.comments = comments
|
||||
self.mentions = mentions
|
||||
self.subscriptions = subscriptions
|
||||
self.upvotes = upvotes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationFeed.UnreadNumbers {
|
||||
struct CodingData: Codable {
|
||||
let all: Int
|
||||
let comments: Int
|
||||
let mentions: Int
|
||||
let subs: Int
|
||||
let upvotes: Int
|
||||
//let total: Int //Not needed because it's the same as `all`.
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationFeed.UnreadNumbers.CodingData {
|
||||
var decoded: NotificationFeed.UnreadNumbers {
|
||||
.init(
|
||||
all: all,
|
||||
comments: comments,
|
||||
mentions: mentions,
|
||||
subscriptions: subs,
|
||||
upvotes: upvotes
|
||||
)
|
||||
}
|
||||
}
|
49
Sources/SwiftDevRant/Models/NotificationFeed.UserInfo.swift
Normal file
49
Sources/SwiftDevRant/Models/NotificationFeed.UserInfo.swift
Normal file
@ -0,0 +1,49 @@
|
||||
public extension NotificationFeed {
|
||||
struct UserInfo: Hashable {
|
||||
public let avatar: User.Avatar
|
||||
public let username: String
|
||||
public let userId: String //TODO: why is this String? The other user ids are Int.
|
||||
|
||||
public init(avatar: User.Avatar, username: String, userId: String) {
|
||||
self.avatar = avatar
|
||||
self.username = username
|
||||
self.userId = userId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationFeed.UserInfo {
|
||||
struct CodingData: Decodable {
|
||||
struct Container: Decodable {
|
||||
let array: [CodingData]
|
||||
}
|
||||
|
||||
let avatar: User.Avatar.CodingData
|
||||
let name: String
|
||||
let uidForUsername: String //TODO: why is this String? The other user ids are Int.
|
||||
|
||||
private enum CodingKeys: CodingKey {
|
||||
case avatar
|
||||
case name
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
avatar = try values.decode(User.Avatar.CodingData.self, forKey: .avatar)
|
||||
name = try values.decode(String.self, forKey: .name)
|
||||
|
||||
uidForUsername = values.codingPath[values.codingPath.endIndex - 1].stringValue //TODO: wtf is this? Check if it can be made simpler and easier to understand.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationFeed.UserInfo.CodingData {
|
||||
var decoded: NotificationFeed.UserInfo {
|
||||
.init(
|
||||
avatar: avatar.decoded,
|
||||
username: name,
|
||||
userId: uidForUsername
|
||||
)
|
||||
}
|
||||
}
|
51
Sources/SwiftDevRant/Models/NotificationFeed.swift
Normal file
51
Sources/SwiftDevRant/Models/NotificationFeed.swift
Normal file
@ -0,0 +1,51 @@
|
||||
import Foundation
|
||||
|
||||
/// Contains a list of all notifications for the logged in user and the numbers of unread notifications.
|
||||
public struct NotificationFeed: Hashable {
|
||||
public enum Categories: String, CaseIterable {
|
||||
case all = ""
|
||||
case upvotes = "upvotes"
|
||||
case mentions = "mentions"
|
||||
case comments = "comments"
|
||||
case subscriptions = "subs"
|
||||
}
|
||||
|
||||
/// The time when the notifications were last checked.
|
||||
public let lastChecked: Date
|
||||
|
||||
/// The list of all notifications for the logged in user.
|
||||
public let notifications: [Notification]
|
||||
|
||||
/// The numbers of unread notifications.
|
||||
public let unreadNumbers: UnreadNumbers
|
||||
|
||||
/// Infos about the user name and avatar for each user id.
|
||||
public let userInfos: [UserInfo]
|
||||
|
||||
public init(lastChecked: Date, notifications: [Notification], unreadNumbers: NotificationFeed.UnreadNumbers, userInfos: [UserInfo]) {
|
||||
self.lastChecked = lastChecked
|
||||
self.notifications = notifications
|
||||
self.unreadNumbers = unreadNumbers
|
||||
self.userInfos = userInfos
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationFeed {
|
||||
struct CodingData: Decodable {
|
||||
let check_time: Int
|
||||
let items: [Notification.CodingData]
|
||||
let unread: UnreadNumbers.CodingData
|
||||
let username_map: UserInfo.CodingData.Container
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationFeed.CodingData {
|
||||
var decoded: NotificationFeed {
|
||||
.init(
|
||||
lastChecked: Date(timeIntervalSince1970: TimeInterval(check_time)),
|
||||
notifications: items.map(\.decoded),
|
||||
unreadNumbers: unread.decoded,
|
||||
userInfos: username_map.array.map(\.decoded)
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user