Skip to content

Commit

Permalink
feat: improvement URL string decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
makinosp committed Aug 2, 2024
1 parent 0a81bc8 commit 22342d9
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 73 deletions.
50 changes: 33 additions & 17 deletions Sources/VRCKit/Models/FriendModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ extension Friend: ProfileElementRepresentable, LocationRepresentable {}
public struct Friend {
public let bio: String?
public var bioLinks: SafeDecodingArray<URL>
public let currentAvatarImageUrl: String?
public let currentAvatarThumbnailImageUrl: String?
public let avatarImageUrl: URL?
public let avatarThumbnailUrl: URL?
public let displayName: String
public let id: String
public let isFriend: Bool
public let lastLogin: Date
public let lastPlatform: String
public let profilePicOverride: String?
public let profilePicOverride: URL?
public let status: UserStatus
public let statusDescription: String
public let tags: [Tag]
public let userIcon: String?
public let userIcon: URL?
public let location: String
public let friendKey: String
}
Expand All @@ -32,34 +32,50 @@ extension Friend: Codable {
public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
bio = try container.decodeIfPresent(String.self, forKey: .bio)
bioLinks = try container.decodeIfPresent(
SafeDecodingArray<URL>.self,
forKey: .bioLinks
) ?? SafeDecodingArray()
currentAvatarImageUrl = try container.decodeIfPresent(String.self, forKey: .currentAvatarImageUrl)
currentAvatarThumbnailImageUrl = try container.decodeIfPresent(
String.self,
forKey: .currentAvatarThumbnailImageUrl
)
bioLinks = try container.decodeSafeNullableArray(URL.self, forKey: .bioLinks)
avatarImageUrl = try container.decodeIfPresent(URL.self, forKey: .avatarImageUrl)
avatarThumbnailUrl = try container.decodeIfPresent(URL.self, forKey: .avatarThumbnailUrl)
displayName = try container.decode(String.self, forKey: .displayName)
id = try container.decode(String.self, forKey: .id)
isFriend = try container.decode(Bool.self, forKey: .isFriend)
lastLogin = try container.decode(Date.self, forKey: .lastLogin)
lastPlatform = try container.decode(String.self, forKey: .lastPlatform)
profilePicOverride = try container.decodeIfPresent(String.self, forKey: .profilePicOverride)
profilePicOverride = try? container.decodeIfPresent(URL.self, forKey: .profilePicOverride)
status = try container.decode(UserStatus.self, forKey: .status)
statusDescription = try container.decode(String.self, forKey: .statusDescription)
tags = try container.decode([Tag].self, forKey: .tags)
userIcon = try container.decodeIfPresent(String.self, forKey: .userIcon)
userIcon = try? container.decodeIfPresent(URL.self, forKey: .userIcon)
location = try container.decode(String.self, forKey: .location)
friendKey = try container.decode(String.self, forKey: .friendKey)
}
}

extension FriendsLocation: LocationRepresentable {}
extension Friend {
private enum CodingKeys: String, CodingKey {
case bio
case bioLinks
case avatarImageUrl = "currentAvatarImageUrl"
case avatarThumbnailUrl = "currentAvatarThumbnailImageUrl"
case displayName
case id
case isFriend
case lastLogin
case lastPlatform
case profilePicOverride
case status
case statusDescription
case tags
case userIcon
case location
case friendKey
}
}

public struct FriendsLocation: Identifiable, Hashable {
public struct FriendsLocation: LocationRepresentable {
public let location: String
public let friends: [Friend]
}

extension FriendsLocation: Hashable, Identifiable {
public var id: String { location }
}
49 changes: 34 additions & 15 deletions Sources/VRCKit/Models/UserDetailModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ public typealias Tag = String
public struct UserDetail {
public var bio: String?
public var bioLinks: SafeDecodingArray<URL>
public let currentAvatarImageUrl: String?
public let currentAvatarThumbnailImageUrl: String?
public let avatarImageUrl: URL?
public let avatarThumbnailUrl: URL?
public let displayName: String
public let id: String
public let isFriend: Bool
public let lastLogin: Date
public let lastPlatform: String
public let profilePicOverride: String?
public let profilePicOverride: URL?
public let state: User.State
public let status: UserStatus
public var statusDescription: String
public var tags: [Tag]
public let userIcon: String?
public let userIcon: URL?
public let location: String
public let friendKey: String
public let dateJoined: String
Expand All @@ -38,26 +38,20 @@ extension UserDetail: Codable {
public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
bio = try container.decodeIfPresent(String.self, forKey: .bio)
bioLinks = try container.decodeIfPresent(
SafeDecodingArray<URL>.self,
forKey: .bioLinks
) ?? SafeDecodingArray()
currentAvatarImageUrl = try container.decodeIfPresent(String.self, forKey: .currentAvatarImageUrl)
currentAvatarThumbnailImageUrl = try container.decodeIfPresent(
String.self,
forKey: .currentAvatarThumbnailImageUrl
)
bioLinks = try container.decodeSafeNullableArray(URL.self, forKey: .bioLinks)
avatarImageUrl = try? container.decodeIfPresent(URL.self, forKey: .avatarImageUrl)
avatarThumbnailUrl = try? container.decodeIfPresent(URL.self, forKey: .avatarThumbnailUrl)
displayName = try container.decode(String.self, forKey: .displayName)
id = try container.decode(String.self, forKey: .id)
isFriend = try container.decode(Bool.self, forKey: .isFriend)
lastLogin = try container.decode(Date.self, forKey: .lastLogin)
lastPlatform = try container.decode(String.self, forKey: .lastPlatform)
profilePicOverride = try container.decodeIfPresent(String.self, forKey: .profilePicOverride)
profilePicOverride = try? container.decodeIfPresent(URL.self, forKey: .profilePicOverride)
state = try container.decode(User.State.self, forKey: .state)
status = try container.decode(UserStatus.self, forKey: .status)
statusDescription = try container.decode(String.self, forKey: .statusDescription)
tags = try container.decode([Tag].self, forKey: .tags)
userIcon = try container.decodeIfPresent(String.self, forKey: .userIcon)
userIcon = try? container.decodeIfPresent(URL.self, forKey: .userIcon)
location = try container.decode(String.self, forKey: .location)
friendKey = try container.decode(String.self, forKey: .friendKey)
dateJoined = try container.decode(String.self, forKey: .dateJoined)
Expand All @@ -66,6 +60,31 @@ extension UserDetail: Codable {
}
}

extension UserDetail {
private enum CodingKeys: String, CodingKey {
case bio
case bioLinks
case avatarImageUrl = "currentAvatarImageUrl"
case avatarThumbnailUrl = "currentAvatarThumbnailImageUrl"
case displayName
case id
case isFriend
case lastLogin
case lastPlatform
case profilePicOverride
case state
case status
case statusDescription
case tags
case userIcon
case location
case friendKey
case dateJoined
case note
case lastActivity
}
}

public struct EditableUserInfo: Codable, Hashable {
public var bio: String
public var bioLinks: [URL]
Expand Down
60 changes: 43 additions & 17 deletions Sources/VRCKit/Models/UserModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ public struct User: ProfileDetailRepresentable {
public let bio: String?
public var bioLinks: SafeDecodingArray<URL>
public let currentAvatar: String
public let currentAvatarAssetUrl: String
public let currentAvatarImageUrl: String?
public let currentAvatarThumbnailImageUrl: String?
public let avatarImageUrl: URL?
public let avatarThumbnailUrl: URL?
public let dateJoined: String
public let displayName: String
public let friendKey: String
Expand All @@ -29,13 +28,13 @@ public struct User: ProfileDetailRepresentable {
public let offlineFriends: [String]
public let onlineFriends: [String]
public let pastDisplayNames: [DisplayName]
public let profilePicOverride: String?
public let profilePicOverride: URL?
public let state: State
public let status: UserStatus
public let statusDescription: String
public let tags: [Tag]
public let twoFactorAuthEnabled: Bool
public let userIcon: String?
public let userIcon: URL?
public let userLanguage: String?
public let userLanguageCode: String?

Expand All @@ -60,17 +59,10 @@ extension User: Codable {
activeFriends = try container.decode([String].self, forKey: .activeFriends)
allowAvatarCopying = try container.decode(Bool.self, forKey: .allowAvatarCopying)
bio = try container.decodeIfPresent(String.self, forKey: .bio)
bioLinks = try container.decodeIfPresent(
SafeDecodingArray<URL>.self,
forKey: .bioLinks
) ?? SafeDecodingArray()
bioLinks = try container.decodeSafeNullableArray(URL.self, forKey: .bioLinks)
currentAvatar = try container.decode(String.self, forKey: .currentAvatar)
currentAvatarAssetUrl = try container.decode(String.self, forKey: .currentAvatarAssetUrl)
currentAvatarImageUrl = try container.decodeIfPresent(String.self, forKey: .currentAvatarImageUrl)
currentAvatarThumbnailImageUrl = try container.decodeIfPresent(
String.self,
forKey: .currentAvatarThumbnailImageUrl
)
avatarImageUrl = try? container.decodeIfPresent(URL.self, forKey: .avatarImageUrl)
avatarThumbnailUrl = try? container.decodeIfPresent(URL.self, forKey: .avatarThumbnailUrl)
dateJoined = try container.decode(String.self, forKey: .dateJoined)
displayName = try container.decode(String.self, forKey: .displayName)
friendKey = try container.decode(String.self, forKey: .friendKey)
Expand All @@ -84,18 +76,52 @@ extension User: Codable {
offlineFriends = try container.decode([String].self, forKey: .offlineFriends)
onlineFriends = try container.decode([String].self, forKey: .onlineFriends)
pastDisplayNames = try container.decode([User.DisplayName].self, forKey: .pastDisplayNames)
profilePicOverride = try container.decodeIfPresent(String.self, forKey: .profilePicOverride)
profilePicOverride = try? container.decodeIfPresent(URL.self, forKey: .profilePicOverride)
state = try container.decode(User.State.self, forKey: .state)
status = try container.decode(UserStatus.self, forKey: .status)
statusDescription = try container.decode(String.self, forKey: .statusDescription)
tags = try container.decode([Tag].self, forKey: .tags)
twoFactorAuthEnabled = try container.decode(Bool.self, forKey: .twoFactorAuthEnabled)
userIcon = try container.decodeIfPresent(String.self, forKey: .userIcon)
userIcon = try? container.decodeIfPresent(URL.self, forKey: .userIcon)
userLanguage = try container.decodeIfPresent(String.self, forKey: .userLanguage)
userLanguageCode = try container.decodeIfPresent(String.self, forKey: .userLanguageCode)
}
}

extension User {
private enum CodingKeys: String, CodingKey {
case activeFriends
case allowAvatarCopying
case bio
case bioLinks
case currentAvatar
case avatarImageUrl = "currentAvatarImageUrl"
case avatarThumbnailUrl = "currentAvatarThumbnailImageUrl"
case dateJoined
case displayName
case friendKey
case friends
case homeLocation
case id
case isFriend
case lastActivity
case lastLogin
case lastPlatform
case offlineFriends
case onlineFriends
case pastDisplayNames
case profilePicOverride
case state
case status
case statusDescription
case tags
case twoFactorAuthEnabled
case userIcon
case userLanguage
case userLanguageCode
}
}

public struct UpdatedUser: Codable {
public let bio: String?
public let statusDescription: String?
Expand Down
19 changes: 9 additions & 10 deletions Sources/VRCKit/PreviewServices/PreviewDataProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,8 @@ final class PreviewDataProvider {
bio: "This is the demo user.",
bioLinks: SafeDecodingArray(),
currentAvatar: "",
currentAvatarAssetUrl: "",
currentAvatarImageUrl: "",
currentAvatarThumbnailImageUrl: "",
avatarImageUrl: nil,
avatarThumbnailUrl: nil,
dateJoined: "2024/07/01",
displayName: "usr_\(previewUserId.uuidString.prefix(8))",
friendKey: "",
Expand All @@ -87,7 +86,7 @@ final class PreviewDataProvider {
statusDescription: "status",
tags: [],
twoFactorAuthEnabled: true,
userIcon: "https://ul.h3z.jp/9gGIcerr.png",
userIcon: URL(string: "https://ul.h3z.jp/9gGIcerr.png"),
userLanguage: nil,
userLanguageCode: nil
)
Expand Down Expand Up @@ -121,8 +120,8 @@ final class PreviewDataProvider {
Friend(
bio: nil,
bioLinks: SafeDecodingArray(),
currentAvatarImageUrl: nil,
currentAvatarThumbnailImageUrl: nil,
avatarImageUrl: nil,
avatarThumbnailUrl: nil,
displayName: "User_\(id.uuidString.prefix(8))",
id: "usr_\(id.uuidString)",
isFriend: true,
Expand All @@ -132,7 +131,7 @@ final class PreviewDataProvider {
status: status,
statusDescription: "",
tags: [],
userIcon: "https://ul.h3z.jp/9gGIcerr.png",
userIcon: URL(string: "https://ul.h3z.jp/9gGIcerr.png"),
location: location,
friendKey: ""
)
Expand All @@ -148,8 +147,8 @@ final class PreviewDataProvider {
UserDetail(
bio: "Demo",
bioLinks: SafeDecodingArray(),
currentAvatarImageUrl: nil,
currentAvatarThumbnailImageUrl: nil,
avatarImageUrl: nil,
avatarThumbnailUrl: nil,
displayName: "User_\(id.uuidString.prefix(8))",
id: "usr_\(id.uuidString)",
isFriend: isFriend,
Expand All @@ -160,7 +159,7 @@ final class PreviewDataProvider {
status: status,
statusDescription: "Demo",
tags: [],
userIcon: "https://ul.h3z.jp/9gGIcerr.png",
userIcon: URL(string: "https://ul.h3z.jp/9gGIcerr.png"),
location: location,
friendKey: "",
dateJoined: "",
Expand Down
28 changes: 14 additions & 14 deletions Sources/VRCKit/Protocols/ProfileProtocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ import Foundation
public protocol ProfileElementRepresentable: Hashable, Identifiable {
var bio: String? { get }
var bioLinks: SafeDecodingArray<URL> { get }
var currentAvatarImageUrl: String? { get }
var currentAvatarThumbnailImageUrl: String? { get }
var avatarImageUrl: URL? { get }
var avatarThumbnailUrl: URL? { get }
var displayName: String { get }
var id: String { get }
var isFriend: Bool { get }
var lastLogin: Date { get }
var lastPlatform: String { get }
var profilePicOverride: String? { get }
var profilePicOverride: URL? { get }
var status: UserStatus { get }
var statusDescription: String { get }
var tags: [Tag] { get }
var userIcon: String? { get }
var userIcon: URL? { get }
var friendKey: String { get }
}

Expand All @@ -37,20 +37,20 @@ public protocol ProfileDetailRepresentable: ProfileElementRepresentable {

public extension ProfileElementRepresentable {
var thumbnailUrl: URL? {
if let userIcon = userIcon, !userIcon.isEmpty {
return URL(string: userIcon)
if let userIcon = userIcon {
return userIcon
}
guard let url = currentAvatarThumbnailImageUrl,
let urlString = url.hasSuffix("256")
? String(url.dropLast(3)) + "512"
: currentAvatarImageUrl else { return nil }
guard let url = avatarThumbnailUrl,
let urlString = url.absoluteString.hasSuffix("256")
? String(url.absoluteString.dropLast(3)) + "512"
: avatarImageUrl?.absoluteString else { return nil }
return URL(string: urlString)
}

var userIconUrl: URL? {
guard let urlString = userIcon?.isEmpty ?? false
? currentAvatarThumbnailImageUrl
: userIcon else { return nil }
return URL(string: urlString)
if let userIcon = userIcon {
return userIcon
}
return avatarThumbnailUrl
}
}

0 comments on commit 22342d9

Please sign in to comment.