From 337a2b639ecafc5159eb0d2af49391a95ad1637a Mon Sep 17 00:00:00 2001 From: Pinar Olguc Date: Mon, 1 Jul 2024 17:49:31 +0300 Subject: [PATCH] Decouple avatarID from Profile model (#304) * Decouple the avatar identifier from the model * Update demo app * Update minor version * Allow warnings * Use `profileIdentifier?.avatarIdentifier in the demo screen. --- .buildkite/commands/publish-pod.sh | 2 +- .buildkite/commands/validate-pods.sh | 4 ++-- .../DemoProfileConfigurationViewController.swift | 2 ++ .../DemoProfilePresentationStylesViewController.swift | 5 +++-- .../Gravatar-Demo/DemoProfileViewsViewController.swift | 9 +++++---- Sources/Gravatar/Identifiers/ProfileIdentifier.swift | 10 ++++++++++ Sources/GravatarUI/ProfileView/BaseProfileView.swift | 7 +++++-- .../ProfileView/ProfileViewConfiguration.swift | 8 ++++++++ .../ProfileViewController/ProfileViewController.swift | 3 +++ version.rb | 2 +- 10 files changed, 40 insertions(+), 12 deletions(-) diff --git a/.buildkite/commands/publish-pod.sh b/.buildkite/commands/publish-pod.sh index a08d2518..896dca2a 100755 --- a/.buildkite/commands/publish-pod.sh +++ b/.buildkite/commands/publish-pod.sh @@ -12,7 +12,7 @@ echo "--- :rubygems: Setting up Gems" install_gems echo "--- :cocoapods: Publishing $PODSPEC_PATH to CocoaPods CDN" -publish_pod --synchronous "$PODSPEC_PATH" +publish_pod --allow-warnings --synchronous "$PODSPEC_PATH" echo "--- :slack: Notifying Slack" slack_notify_pod_published "$PODSPEC_PATH" "$SLACK_WEBHOOK" diff --git a/.buildkite/commands/validate-pods.sh b/.buildkite/commands/validate-pods.sh index 6dee87bb..a3228ecb 100644 --- a/.buildkite/commands/validate-pods.sh +++ b/.buildkite/commands/validate-pods.sh @@ -1,7 +1,7 @@ #!/bin/bash -eu echo "--- :cocoapods: Validate Gravatar.podspec" -validate_podspec Gravatar.podspec +validate_podspec --allow-warnings Gravatar.podspec echo "--- :cocoapods: Validate GravatarUI.podspec" -validate_podspec GravatarUI.podspec +validate_podspec --allow-warnings GravatarUI.podspec diff --git a/Demo/Demo/Gravatar-Demo/DemoProfileConfigurationViewController.swift b/Demo/Demo/Gravatar-Demo/DemoProfileConfigurationViewController.swift index 50b27f70..7cf14aec 100644 --- a/Demo/Demo/Gravatar-Demo/DemoProfileConfigurationViewController.swift +++ b/Demo/Demo/Gravatar-Demo/DemoProfileConfigurationViewController.swift @@ -66,6 +66,7 @@ class DemoProfileConfigurationViewController: UITableViewController { guard !email.isEmpty else { return } var config = ProfileViewConfiguration.standard() + config.avatarIdentifier = .email(email) config.isLoading = true models[email] = config snapshot.appendItems([email]) @@ -75,6 +76,7 @@ class DemoProfileConfigurationViewController: UITableViewController { do { let profile = try await service.fetch(with: .email(email)) models[email] = .standard(model: profile) + models[email]?.avatarIdentifier = .email(email) snapshot.reloadItems([email]) await dataSource.apply(snapshot) } catch APIError.responseError(let reason) where reason.httpStatusCode == 404 { diff --git a/Demo/Demo/Gravatar-Demo/DemoProfilePresentationStylesViewController.swift b/Demo/Demo/Gravatar-Demo/DemoProfilePresentationStylesViewController.swift index 4724b8d8..45e40af1 100644 --- a/Demo/Demo/Gravatar-Demo/DemoProfilePresentationStylesViewController.swift +++ b/Demo/Demo/Gravatar-Demo/DemoProfilePresentationStylesViewController.swift @@ -35,7 +35,7 @@ class DemoProfilePresentationStylesViewController: DemoBaseProfileViewController } } else { - let viewController = ProfileViewController(configuration: newConfig(), viewModel: .init(), profileIdentifier: profileIdentifier) + let viewController = ProfileViewController(configuration: newConfig(profileIdentifier: profileIdentifier), viewModel: .init(), profileIdentifier: profileIdentifier) self.profileViewController = viewController presentInBottomSheet(viewController) } @@ -74,7 +74,7 @@ class DemoProfilePresentationStylesViewController: DemoBaseProfileViewController bottomSheetNavigationViewController?.navigationBar.scrollEdgeAppearance = appearance } - func newConfig() -> ProfileViewConfiguration { + func newConfig(profileIdentifier: ProfileIdentifier?) -> ProfileViewConfiguration { var config: ProfileViewConfiguration switch preferredProfileStyle { case .large: @@ -86,6 +86,7 @@ class DemoProfilePresentationStylesViewController: DemoBaseProfileViewController case .summary: config = ProfileViewConfiguration.summary(palette: preferredPaletteType) } + config.avatarIdentifier = profileIdentifier?.avatarIdentifier if customizeAvatarSwitchWithLabel.isOn { config.avatarConfiguration.borderColor = .green config.avatarConfiguration.borderWidth = 3 diff --git a/Demo/Demo/Gravatar-Demo/DemoProfileViewsViewController.swift b/Demo/Demo/Gravatar-Demo/DemoProfileViewsViewController.swift index b87d7bf6..fc10d5e9 100644 --- a/Demo/Demo/Gravatar-Demo/DemoProfileViewsViewController.swift +++ b/Demo/Demo/Gravatar-Demo/DemoProfileViewsViewController.swift @@ -84,6 +84,11 @@ class DemoProfileViewsViewController: DemoBaseProfileViewController { guard largeProfileView.isLoading == false else { return } + largeProfileView.loadAvatar(with: .email(email), defaultAvatarOption: .status404, options: [.transition(.fade(0.2))]) + largeProfileSummaryView.loadAvatar(with: .email(email), defaultAvatarOption: .status404, options: [.transition(.fade(0.2))]) + profileView.loadAvatar(with: .email(email), defaultAvatarOption: .status404, options: [.transition(.fade(0.2))]) + profileSummaryView.loadAvatar(with: .email(email), defaultAvatarOption: .status404, options: [.transition(.fade(0.2))]) + updateLoading(isLoading: true) let service = ProfileService() Task { @@ -92,16 +97,12 @@ class DemoProfileViewsViewController: DemoBaseProfileViewController { let profile = try await service.fetch(with: identifier) largeProfileView.update(with: profile) largeProfileView.profileButtonStyle = .view - largeProfileView.loadAvatar(with: profile.avatarIdentifier, options: [.transition(.fade(0.2))]) largeProfileSummaryView.update(with: profile) largeProfileSummaryView.profileButtonStyle = .view - largeProfileSummaryView.loadAvatar(with: profile.avatarIdentifier, options: [.transition(.fade(0.2))]) profileView.update(with: profile) profileView.profileButtonStyle = .view - profileView.loadAvatar(with: profile.avatarIdentifier, options: [.transition(.fade(0.2))]) profileSummaryView.update(with: profile) profileSummaryView.profileButtonStyle = .view - profileSummaryView.loadAvatar(with: profile.avatarIdentifier, options: [.transition(.fade(0.2))]) } catch APIError.responseError(reason: let reason) where reason.httpStatusCode == 404 { largeProfileView.updateWithClaimProfilePrompt() largeProfileSummaryView.updateWithClaimProfilePrompt() diff --git a/Sources/Gravatar/Identifiers/ProfileIdentifier.swift b/Sources/Gravatar/Identifiers/ProfileIdentifier.swift index 257e59bb..f0986f0d 100644 --- a/Sources/Gravatar/Identifiers/ProfileIdentifier.swift +++ b/Sources/Gravatar/Identifiers/ProfileIdentifier.swift @@ -37,4 +37,14 @@ extension ProfileIdentifier: Identifiable { hashID.id } } + + // Returns the `AvatarIdentifier` popuplated from `self`. + public var avatarIdentifier: AvatarIdentifier { + switch self { + case .email(let email): + AvatarIdentifier.email(email.string) + case .hashID(let hashID): + AvatarIdentifier.hashID(hashID.string) + } + } } diff --git a/Sources/GravatarUI/ProfileView/BaseProfileView.swift b/Sources/GravatarUI/ProfileView/BaseProfileView.swift index 0493703a..91246fc8 100644 --- a/Sources/GravatarUI/ProfileView/BaseProfileView.swift +++ b/Sources/GravatarUI/ProfileView/BaseProfileView.swift @@ -99,6 +99,8 @@ open class BaseProfileView: UIView, UIContentView { } } + private var avatarIdentifier: AvatarIdentifier? + var padding: UIEdgeInsets { get { // layoutMargins is automatically synced with directionalLayoutMargins @@ -288,6 +290,7 @@ open class BaseProfileView: UIView, UIContentView { defaultAvatarOption: DefaultAvatarOption? = nil, options: [ImageSettingOption]? = nil ) { + self.avatarIdentifier = avatarIdentifier guard let avatarIdentifier else { avatarProvider.setImage(placeholder) return @@ -407,7 +410,7 @@ open class BaseProfileView: UIView, UIContentView { private func loadAvatar(with config: ProfileViewConfiguration) { loadAvatar( - with: config.avatarID, + with: config.avatarIdentifier ?? config.avatarID, placeholder: config.avatarConfiguration.placeholder, rating: config.avatarConfiguration.rating, defaultAvatarOption: config.avatarConfiguration.defaultAvatarOption, @@ -426,7 +429,7 @@ open class BaseProfileView: UIView, UIContentView { @objc private func avatarTapped() { - delegate?.profileView(self, didTapOnAvatarWithID: model?.avatarIdentifier) + delegate?.profileView(self, didTapOnAvatarWithID: avatarIdentifier) } // MARK: - Placeholder handling diff --git a/Sources/GravatarUI/ProfileView/ProfileViewConfiguration.swift b/Sources/GravatarUI/ProfileView/ProfileViewConfiguration.swift index 9f73fa51..2ec844fb 100644 --- a/Sources/GravatarUI/ProfileView/ProfileViewConfiguration.swift +++ b/Sources/GravatarUI/ProfileView/ProfileViewConfiguration.swift @@ -24,10 +24,18 @@ public struct ProfileViewConfiguration: UIContentConfiguration { /// The style for the profile view. public let profileStyle: Style /// The identifier for the avatar image to be loaded in the profile view. + @available( + *, + deprecated, + renamed: "avatarIdentifier", + message: "Set `avatarIdentifier` explicitly and don't use the model's avatarIdentifier. It's because the `ProfileModel.avatarIdentifier` always refers to the primary email's avatar even if we query the profile with a secondary email." + ) var avatarID: AvatarIdentifier? { model?.avatarIdentifier ?? summaryModel?.avatarIdentifier } + /// The identifier for the avatar image to be loaded in the profile view. + public var avatarIdentifier: AvatarIdentifier? /// The palette to be used to style the view. public var palette: PaletteType /// Creates a padding space around the content of the profile view. diff --git a/Sources/GravatarUI/ProfileViewController/ProfileViewController.swift b/Sources/GravatarUI/ProfileViewController/ProfileViewController.swift index 1388baa1..72384e6e 100644 --- a/Sources/GravatarUI/ProfileViewController/ProfileViewController.swift +++ b/Sources/GravatarUI/ProfileViewController/ProfileViewController.swift @@ -91,6 +91,9 @@ public class ProfileViewController: UIViewController { } public func fetchProfile(profileIdentifier: ProfileIdentifier) { + var newConfig = self.configuration + newConfig.avatarIdentifier = profileIdentifier.avatarIdentifier + self.configuration = newConfig Task { await viewModel.fetchProfile(profileIdentifier: profileIdentifier) } diff --git a/version.rb b/version.rb index e0b0363c..370afeb6 100644 --- a/version.rb +++ b/version.rb @@ -1,3 +1,3 @@ module Gravatar - VERSION = '2.0.2'.freeze + VERSION = '2.1.0'.freeze end