2022-11-20 15:39:06 +00:00
|
|
|
import Foundation
|
|
|
|
|
2023-02-21 11:35:07 +00:00
|
|
|
public final class Account: Codable, Identifiable, Hashable, Sendable, Equatable {
|
2023-02-18 06:15:57 +00:00
|
|
|
public static func == (lhs: Account, rhs: Account) -> Bool {
|
2023-02-21 11:35:07 +00:00
|
|
|
lhs.id == rhs.id &&
|
2023-02-22 18:09:39 +00:00
|
|
|
lhs.username == rhs.username &&
|
|
|
|
lhs.note.asRawText == rhs.note.asRawText &&
|
|
|
|
lhs.statusesCount == rhs.statusesCount &&
|
|
|
|
lhs.followersCount == rhs.followersCount &&
|
|
|
|
lhs.followingCount == rhs.followingCount &&
|
|
|
|
lhs.acct == rhs.acct &&
|
|
|
|
lhs.displayName == rhs.displayName &&
|
|
|
|
lhs.fields == rhs.fields &&
|
|
|
|
lhs.lastStatusAt == rhs.lastStatusAt &&
|
|
|
|
lhs.discoverable == rhs.discoverable &&
|
2023-02-24 06:55:24 +00:00
|
|
|
lhs.bot == rhs.bot &&
|
2024-01-02 20:16:27 +00:00
|
|
|
lhs.locked == rhs.locked &&
|
|
|
|
lhs.avatar == rhs.avatar &&
|
|
|
|
lhs.header == rhs.header
|
2023-02-18 06:15:57 +00:00
|
|
|
}
|
2023-02-18 06:26:48 +00:00
|
|
|
|
2022-12-17 12:37:46 +00:00
|
|
|
public func hash(into hasher: inout Hasher) {
|
|
|
|
hasher.combine(id)
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-02-18 21:51:44 +00:00
|
|
|
public struct Field: Codable, Equatable, Identifiable, Sendable {
|
2022-12-21 19:53:23 +00:00
|
|
|
public var id: String {
|
2023-01-20 17:27:00 +00:00
|
|
|
value.asRawText + name
|
2022-12-21 19:53:23 +00:00
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-17 12:37:46 +00:00
|
|
|
public let name: String
|
2022-12-21 19:53:23 +00:00
|
|
|
public let value: HTMLString
|
2022-12-17 12:37:46 +00:00
|
|
|
public let verifiedAt: String?
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-02-18 21:51:44 +00:00
|
|
|
public struct Source: Codable, Equatable, Sendable {
|
2023-01-10 07:24:05 +00:00
|
|
|
public let privacy: Visibility
|
|
|
|
public let sensitive: Bool
|
|
|
|
public let language: String?
|
|
|
|
public let note: String
|
|
|
|
public let fields: [Field]
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-11-20 15:39:06 +00:00
|
|
|
public let id: String
|
|
|
|
public let username: String
|
2023-03-02 19:15:07 +00:00
|
|
|
public let displayName: String?
|
2024-01-24 15:22:44 +00:00
|
|
|
public let cachedDisplayName: HTMLString
|
2022-11-20 15:39:06 +00:00
|
|
|
public let avatar: URL
|
2022-12-17 12:37:46 +00:00
|
|
|
public let header: URL
|
2022-11-21 13:42:59 +00:00
|
|
|
public let acct: String
|
2022-12-17 12:37:46 +00:00
|
|
|
public let note: HTMLString
|
|
|
|
public let createdAt: ServerDate
|
2023-07-04 06:37:30 +00:00
|
|
|
public let followersCount: Int?
|
|
|
|
public let followingCount: Int?
|
|
|
|
public let statusesCount: Int?
|
2022-12-17 12:37:46 +00:00
|
|
|
public let lastStatusAt: String?
|
|
|
|
public let fields: [Field]
|
|
|
|
public let locked: Bool
|
2022-12-21 16:39:48 +00:00
|
|
|
public let emojis: [Emoji]
|
2023-01-04 17:37:58 +00:00
|
|
|
public let url: URL?
|
2023-01-10 07:24:05 +00:00
|
|
|
public let source: Source?
|
|
|
|
public let bot: Bool
|
|
|
|
public let discoverable: Bool?
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-30 06:15:18 +00:00
|
|
|
public var haveAvatar: Bool {
|
2023-09-16 12:15:03 +00:00
|
|
|
avatar.lastPathComponent != "missing.png"
|
2023-01-30 06:15:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public var haveHeader: Bool {
|
2023-09-16 12:15:03 +00:00
|
|
|
header.lastPathComponent != "missing.png"
|
2023-01-30 06:15:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-02 19:15:07 +00:00
|
|
|
public init(id: String, username: String, displayName: String?, avatar: URL, header: URL, acct: String, note: HTMLString, createdAt: ServerDate, followersCount: Int, followingCount: Int, statusesCount: Int, lastStatusAt: String? = nil, fields: [Account.Field], locked: Bool, emojis: [Emoji], url: URL? = nil, source: Account.Source? = nil, bot: Bool, discoverable: Bool? = nil) {
|
2023-02-18 06:15:57 +00:00
|
|
|
self.id = id
|
|
|
|
self.username = username
|
|
|
|
self.displayName = displayName
|
|
|
|
self.avatar = avatar
|
|
|
|
self.header = header
|
|
|
|
self.acct = acct
|
|
|
|
self.note = note
|
|
|
|
self.createdAt = createdAt
|
|
|
|
self.followersCount = followersCount
|
|
|
|
self.followingCount = followingCount
|
|
|
|
self.statusesCount = statusesCount
|
|
|
|
self.lastStatusAt = lastStatusAt
|
|
|
|
self.fields = fields
|
|
|
|
self.locked = locked
|
|
|
|
self.emojis = emojis
|
|
|
|
self.url = url
|
|
|
|
self.source = source
|
|
|
|
self.bot = bot
|
|
|
|
self.discoverable = discoverable
|
2024-02-14 11:48:14 +00:00
|
|
|
|
2024-01-24 15:22:44 +00:00
|
|
|
if let displayName, !displayName.isEmpty {
|
2024-02-14 11:48:14 +00:00
|
|
|
cachedDisplayName = .init(stringValue: displayName)
|
2024-01-24 15:22:44 +00:00
|
|
|
} else {
|
2024-02-14 11:48:14 +00:00
|
|
|
cachedDisplayName = .init(stringValue: "@\(username)")
|
2024-01-24 15:22:44 +00:00
|
|
|
}
|
|
|
|
}
|
2024-02-14 11:48:14 +00:00
|
|
|
|
2024-01-24 15:22:44 +00:00
|
|
|
public enum CodingKeys: CodingKey {
|
|
|
|
case id
|
|
|
|
case username
|
|
|
|
case displayName
|
|
|
|
case avatar
|
|
|
|
case header
|
|
|
|
case acct
|
|
|
|
case note
|
|
|
|
case createdAt
|
|
|
|
case followersCount
|
|
|
|
case followingCount
|
|
|
|
case statusesCount
|
|
|
|
case lastStatusAt
|
|
|
|
case fields
|
|
|
|
case locked
|
|
|
|
case emojis
|
|
|
|
case url
|
|
|
|
case source
|
|
|
|
case bot
|
|
|
|
case discoverable
|
|
|
|
}
|
2024-02-14 11:48:14 +00:00
|
|
|
|
2024-01-24 15:22:44 +00:00
|
|
|
public init(from decoder: Decoder) throws {
|
|
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
2024-02-14 11:48:14 +00:00
|
|
|
id = try container.decode(String.self, forKey: .id)
|
|
|
|
username = try container.decode(String.self, forKey: .username)
|
|
|
|
displayName = try container.decodeIfPresent(String.self, forKey: .displayName)
|
|
|
|
avatar = try container.decode(URL.self, forKey: .avatar)
|
|
|
|
header = try container.decode(URL.self, forKey: .header)
|
|
|
|
acct = try container.decode(String.self, forKey: .acct)
|
|
|
|
note = try container.decode(HTMLString.self, forKey: .note)
|
|
|
|
createdAt = try container.decode(ServerDate.self, forKey: .createdAt)
|
|
|
|
followersCount = try container.decodeIfPresent(Int.self, forKey: .followersCount)
|
|
|
|
followingCount = try container.decodeIfPresent(Int.self, forKey: .followingCount)
|
|
|
|
statusesCount = try container.decodeIfPresent(Int.self, forKey: .statusesCount)
|
|
|
|
lastStatusAt = try container.decodeIfPresent(String.self, forKey: .lastStatusAt)
|
|
|
|
fields = try container.decode([Account.Field].self, forKey: .fields)
|
|
|
|
locked = try container.decode(Bool.self, forKey: .locked)
|
|
|
|
emojis = try container.decode([Emoji].self, forKey: .emojis)
|
|
|
|
url = try container.decodeIfPresent(URL.self, forKey: .url)
|
|
|
|
source = try container.decodeIfPresent(Account.Source.self, forKey: .source)
|
|
|
|
bot = try container.decode(Bool.self, forKey: .bot)
|
|
|
|
discoverable = try container.decodeIfPresent(Bool.self, forKey: .discoverable)
|
2024-01-24 15:22:44 +00:00
|
|
|
if let displayName, !displayName.isEmpty {
|
2024-02-14 11:48:14 +00:00
|
|
|
cachedDisplayName = .init(stringValue: displayName)
|
2024-01-24 15:22:44 +00:00
|
|
|
} else {
|
2024-02-14 11:48:14 +00:00
|
|
|
cachedDisplayName = .init(stringValue: "@\(username)")
|
2024-01-24 15:22:44 +00:00
|
|
|
}
|
2023-02-18 06:15:57 +00:00
|
|
|
}
|
2023-02-18 06:26:48 +00:00
|
|
|
|
2022-12-17 12:37:46 +00:00
|
|
|
public static func placeholder() -> Account {
|
|
|
|
.init(id: UUID().uuidString,
|
|
|
|
username: "Username",
|
2023-02-08 18:09:24 +00:00
|
|
|
displayName: "John Mastodon",
|
2022-12-17 12:37:46 +00:00
|
|
|
avatar: URL(string: "https://files.mastodon.social/media_attachments/files/003/134/405/original/04060b07ddf7bb0b.png")!,
|
|
|
|
header: URL(string: "https://files.mastodon.social/media_attachments/files/003/134/405/original/04060b07ddf7bb0b.png")!,
|
2023-02-08 18:09:24 +00:00
|
|
|
acct: "johnm@example.com",
|
2023-01-20 17:27:00 +00:00
|
|
|
note: .init(stringValue: "Some content"),
|
2023-02-09 08:12:44 +00:00
|
|
|
createdAt: ServerDate(),
|
2022-12-17 12:37:46 +00:00
|
|
|
followersCount: 10,
|
|
|
|
followingCount: 10,
|
|
|
|
statusesCount: 10,
|
|
|
|
lastStatusAt: nil,
|
|
|
|
fields: [],
|
2022-12-21 16:39:48 +00:00
|
|
|
locked: false,
|
2023-01-04 17:37:58 +00:00
|
|
|
emojis: [],
|
2023-01-10 07:24:05 +00:00
|
|
|
url: nil,
|
|
|
|
source: nil,
|
|
|
|
bot: false,
|
|
|
|
discoverable: true)
|
2022-12-17 12:37:46 +00:00
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2022-12-23 17:47:19 +00:00
|
|
|
public static func placeholders() -> [Account] {
|
|
|
|
[.placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(),
|
|
|
|
.placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder()]
|
|
|
|
}
|
2022-11-20 15:39:06 +00:00
|
|
|
}
|
2022-12-22 11:26:11 +00:00
|
|
|
|
2023-01-20 17:27:00 +00:00
|
|
|
public struct FamiliarAccounts: Decodable {
|
2022-12-22 11:26:11 +00:00
|
|
|
public let id: String
|
|
|
|
public let accounts: [Account]
|
|
|
|
}
|
2023-02-27 05:39:07 +00:00
|
|
|
|
|
|
|
extension FamiliarAccounts: Sendable {}
|