Skip to content

Commit 45936d0

Browse files
committed
feat: implement custom decoder for nullable arrays
1 parent 89da579 commit 45936d0

File tree

3 files changed

+148
-7
lines changed

3 files changed

+148
-7
lines changed

Sources/VRCKit/Models/FriendModel.swift

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import Foundation
99

1010
extension Friend: ProfileElementRepresentable, LocationRepresentable {}
1111

12-
public struct Friend: Codable {
12+
public struct Friend {
1313
public let bio: String?
14-
@NullableArray public var bioLinks: [URL]
14+
public var bioLinks: [String]
1515
public let currentAvatarImageUrl: String?
1616
public let currentAvatarThumbnailImageUrl: String?
1717
public let displayName: String
@@ -26,6 +26,32 @@ public struct Friend: Codable {
2626
public let userIcon: String?
2727
public let location: String
2828
public let friendKey: String
29+
30+
}
31+
32+
extension Friend: Codable {
33+
public init(from decoder: any Decoder) throws {
34+
let container = try decoder.container(keyedBy: CodingKeys.self)
35+
self.bio = try container.decodeIfPresent(String.self, forKey: .bio)
36+
self.bioLinks = try container.decodeIfPresent([String].self, forKey: .bioLinks) ?? []
37+
self.currentAvatarImageUrl = try container.decodeIfPresent(String.self, forKey: .currentAvatarImageUrl)
38+
self.currentAvatarThumbnailImageUrl = try container.decodeIfPresent(
39+
String.self,
40+
forKey: .currentAvatarThumbnailImageUrl
41+
)
42+
self.displayName = try container.decode(String.self, forKey: .displayName)
43+
self.id = try container.decode(String.self, forKey: .id)
44+
self.isFriend = try container.decode(Bool.self, forKey: .isFriend)
45+
self.lastLogin = try container.decode(Date.self, forKey: .lastLogin)
46+
self.lastPlatform = try container.decode(String.self, forKey: .lastPlatform)
47+
self.profilePicOverride = try container.decodeIfPresent(String.self, forKey: .profilePicOverride)
48+
self.status = try container.decode(UserStatus.self, forKey: .status)
49+
self.statusDescription = try container.decode(String.self, forKey: .statusDescription)
50+
self.tags = try container.decode([Tag].self, forKey: .tags)
51+
self.userIcon = try container.decodeIfPresent(String.self, forKey: .userIcon)
52+
self.location = try container.decode(String.self, forKey: .location)
53+
self.friendKey = try container.decode(String.self, forKey: .friendKey)
54+
}
2955
}
3056

3157
extension FriendsLocation: LocationRepresentable {}

Sources/VRCKit/Models/UserDetailModel.swift

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ extension UserDetail: ProfileDetailRepresentable, LocationRepresentable {}
1111

1212
public typealias Tag = String
1313

14-
public struct UserDetail: Codable {
14+
public struct UserDetail {
1515
public var bio: String?
16-
@NullableArray public var bioLinks: [URL]
16+
public var bioLinks: [String]
1717
public let currentAvatarImageUrl: String?
1818
public let currentAvatarThumbnailImageUrl: String?
1919
public let displayName: String
@@ -34,6 +34,35 @@ public struct UserDetail: Codable {
3434
public let lastActivity: Date
3535
}
3636

37+
extension UserDetail: Codable {
38+
public init(from decoder: any Decoder) throws {
39+
let container = try decoder.container(keyedBy: CodingKeys.self)
40+
bio = try container.decodeIfPresent(String.self, forKey: .bio)
41+
bioLinks = try container.decodeIfPresent([String].self, forKey: .bioLinks) ?? []
42+
currentAvatarImageUrl = try container.decodeIfPresent(String.self, forKey: .currentAvatarImageUrl)
43+
currentAvatarThumbnailImageUrl = try container.decodeIfPresent(
44+
String.self,
45+
forKey: .currentAvatarThumbnailImageUrl
46+
)
47+
displayName = try container.decode(String.self, forKey: .displayName)
48+
id = try container.decode(String.self, forKey: .id)
49+
isFriend = try container.decode(Bool.self, forKey: .isFriend)
50+
lastLogin = try container.decode(Date.self, forKey: .lastLogin)
51+
lastPlatform = try container.decode(String.self, forKey: .lastPlatform)
52+
profilePicOverride = try container.decodeIfPresent(String.self, forKey: .profilePicOverride)
53+
state = try container.decode(User.State.self, forKey: .state)
54+
status = try container.decode(UserStatus.self, forKey: .status)
55+
statusDescription = try container.decode(String.self, forKey: .statusDescription)
56+
tags = try container.decode([Tag].self, forKey: .tags)
57+
userIcon = try container.decodeIfPresent(String.self, forKey: .userIcon)
58+
location = try container.decode(String.self, forKey: .location)
59+
friendKey = try container.decode(String.self, forKey: .friendKey)
60+
dateJoined = try container.decode(String.self, forKey: .dateJoined)
61+
note = try container.decode(String.self, forKey: .note)
62+
lastActivity = try container.decode(Date.self, forKey: .lastActivity)
63+
}
64+
}
65+
3766
public struct EditableUserInfo: Codable, Hashable {
3867
public var bio: String
3968
public var bioLinks: [URL]
@@ -43,9 +72,56 @@ public struct EditableUserInfo: Codable, Hashable {
4372

4473
public init(detail: any ProfileDetailRepresentable) {
4574
self.bio = detail.bio ?? ""
46-
self.bioLinks = detail.bioLinks
75+
self.bioLinks = []
4776
self.status = detail.status
4877
self.statusDescription = detail.statusDescription
4978
self.tags = detail.tags
5079
}
5180
}
81+
82+
//public struct Tag: Codable, Hashable {
83+
// public let value: TagValue?
84+
//
85+
// public init(from decoder: any Decoder) throws {
86+
// let container = try decoder.singleValueContainer()
87+
// var someValue: TagValue?
88+
// do {
89+
// someValue = try container.decode(TagValue.self)
90+
// } catch {
91+
// someValue = try .other(try container.decode(String.self))
92+
// }
93+
// self.value = someValue
94+
//
95+
// // for debug
96+
// switch self.value {
97+
// case .systemAvatarAccess, .system_trust_basic, .system_world_access:
98+
// print(value)
99+
// default:
100+
// break
101+
// }
102+
// }
103+
//
104+
// public func encode(to encoder: any Encoder) throws {
105+
// var container = encoder.singleValueContainer()
106+
// try container.encode(self.value)
107+
// }
108+
//}
109+
110+
111+
//public enum Tag: String, Codable, Hashable {
112+
// case systemAvatarAccess
113+
// case system_trust_basic
114+
// case system_world_access
115+
// case unknown
116+
//
117+
// public init(from decoder: Decoder) throws {
118+
// let container = try decoder.singleValueContainer()
119+
// let rawValue = try container.decode(String.self)
120+
// self = Tag(rawValue: rawValue) ?? .unknown
121+
// }
122+
//
123+
// public func encode(to encoder: any Encoder) throws {
124+
// var container = encoder.singleValueContainer()
125+
// try container.encode(self.rawValue)
126+
// }
127+
//}

Sources/VRCKit/Models/UserModel.swift

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

88
import Foundation
99

10-
public struct User: Codable, ProfileDetailRepresentable {
10+
public struct User: ProfileDetailRepresentable {
1111
public let activeFriends: [String]
1212
public let allowAvatarCopying: Bool
1313
public let bio: String?
14-
@NullableArray public var bioLinks: [URL]
14+
public var bioLinks: [String]
1515
public let currentAvatar: String
1616
public let currentAvatarAssetUrl: String
1717
public let currentAvatarImageUrl: String?
@@ -54,6 +54,45 @@ public struct User: Codable, ProfileDetailRepresentable {
5454
}
5555
}
5656

57+
extension User: Codable {
58+
public init(from decoder: any Decoder) throws {
59+
let container = try decoder.container(keyedBy: CodingKeys.self)
60+
self.activeFriends = try container.decode([String].self, forKey: .activeFriends)
61+
self.allowAvatarCopying = try container.decode(Bool.self, forKey: .allowAvatarCopying)
62+
self.bio = try container.decodeIfPresent(String.self, forKey: .bio)
63+
self.bioLinks = try container.decodeIfPresent([String].self, forKey: .bioLinks) ?? []
64+
self.currentAvatar = try container.decode(String.self, forKey: .currentAvatar)
65+
self.currentAvatarAssetUrl = try container.decode(String.self, forKey: .currentAvatarAssetUrl)
66+
self.currentAvatarImageUrl = try container.decodeIfPresent(String.self, forKey: .currentAvatarImageUrl)
67+
self.currentAvatarThumbnailImageUrl = try container.decodeIfPresent(
68+
String.self,
69+
forKey: .currentAvatarThumbnailImageUrl
70+
)
71+
self.dateJoined = try container.decode(String.self, forKey: .dateJoined)
72+
self.displayName = try container.decode(String.self, forKey: .displayName)
73+
self.friendKey = try container.decode(String.self, forKey: .friendKey)
74+
self.friends = try container.decode([String].self, forKey: .friends)
75+
self.homeLocation = try container.decode(String.self, forKey: .homeLocation)
76+
self.id = try container.decode(String.self, forKey: .id)
77+
self.isFriend = try container.decode(Bool.self, forKey: .isFriend)
78+
self.lastActivity = try container.decode(Date.self, forKey: .lastActivity)
79+
self.lastLogin = try container.decode(Date.self, forKey: .lastLogin)
80+
self.lastPlatform = try container.decode(String.self, forKey: .lastPlatform)
81+
self.offlineFriends = try container.decode([String].self, forKey: .offlineFriends)
82+
self.onlineFriends = try container.decode([String].self, forKey: .onlineFriends)
83+
self.pastDisplayNames = try container.decode([User.DisplayName].self, forKey: .pastDisplayNames)
84+
self.profilePicOverride = try container.decodeIfPresent(String.self, forKey: .profilePicOverride)
85+
self.state = try container.decode(User.State.self, forKey: .state)
86+
self.status = try container.decode(UserStatus.self, forKey: .status)
87+
self.statusDescription = try container.decode(String.self, forKey: .statusDescription)
88+
self.tags = try container.decode([Tag].self, forKey: .tags)
89+
self.twoFactorAuthEnabled = try container.decode(Bool.self, forKey: .twoFactorAuthEnabled)
90+
self.userIcon = try container.decodeIfPresent(String.self, forKey: .userIcon)
91+
self.userLanguage = try container.decodeIfPresent(String.self, forKey: .userLanguage)
92+
self.userLanguageCode = try container.decodeIfPresent(String.self, forKey: .userLanguageCode)
93+
}
94+
}
95+
5796
public struct UpdatedUser: Codable {
5897
public let bio: String?
5998
public let statusDescription: String?

0 commit comments

Comments
 (0)