diff --git a/.spi.yml b/.spi.yml index c26f631f..6dbbcd04 100644 --- a/.spi.yml +++ b/.spi.yml @@ -1,6 +1,13 @@ +# This is manifest file for the Swift Package Index for it to auto-generate and +# host DocC documentation. +# +# For reference see https://swiftpackageindex.com/swiftpackageindex/spimanifest/documentation/spimanifest/commonusecases#Host-DocC-documentation-in-the-Swift-Package-Index + version: 1 builder: configs: - - documentation_targets: [Gravatar, GravatarUI] + - documentation_targets: + - GravatarUI + - Gravatar platform: ios custom_documentation_parameters: [--include-extended-types] diff --git a/Makefile b/Makefile index 8f8708f4..280aacf7 100644 --- a/Makefile +++ b/Makefile @@ -41,4 +41,13 @@ validate-pod: bundle-install xcrun simctl list >> /dev/null bundle exec pod lib lint \ --include-podspecs="*.podspec" \ - --verbose --fail-fast \ No newline at end of file + --verbose --fail-fast + +update-example-snapshots: + for filePath in ./Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/*; \ + do rm $$filePath; done + cp ./Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/* ./Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples + # Append @2x to the file name. + cd ./Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples && \ + for filePath in *; do name=$${filePath%.*}; mv $$filePath $${name//-dark/~dark}@2x$${filePath#$$name}; done + diff --git a/Sources/Gravatar/Gravatar.docc/Gravatar.md b/Sources/Gravatar/Gravatar.docc/Gravatar.md index 4a4c4191..c0718a28 100644 --- a/Sources/Gravatar/Gravatar.docc/Gravatar.md +++ b/Sources/Gravatar/Gravatar.docc/Gravatar.md @@ -18,16 +18,17 @@ A Gravatar is a Globally Recognized Avatar. You upload an image and create your This SDK will allow you to easily implement the Gravatar services in your project. -### Displaying a Gravatar Image +### Obtaining a Gravatar Image -The easiest way is to use the `UIImageView.gravatar` extension. +Using the **AvatarService**: ```swift -gravatarImageView.gravatar.setImage(email: "user@email.com") +let service = AvatarService() +let result = try await imageRetriever.fetch(with: .email("some@email.com")) +let avatar = result.image ``` -For more info check: -- `GravatarWrapper/setImage(email:placeholder:rating:preferredSize:defaultAvatarOption:options:completionHandler:)` +For more information, check ``AvatarService``. ## Featured diff --git a/Sources/GravatarUI/GravatarUI.docc/GravatarUI.md b/Sources/GravatarUI/GravatarUI.docc/GravatarUI.md new file mode 100644 index 00000000..adc5d8a3 --- /dev/null +++ b/Sources/GravatarUI/GravatarUI.docc/GravatarUI.md @@ -0,0 +1,44 @@ +# ``GravatarUI`` + +Gravatar iOS SDK + +@Metadata { + @PageImage( + purpose: icon, + source: "gravatar-sdk" + ) +} + +## Overview + +An “avatar” is an image that represents you online—a little picture that appears next to your name when you interact with websites. + +A Gravatar is a Globally Recognized Avatar. You upload an image and create your public profile just once, and then when you participate in any Gravatar-enabled site, your Gravatar image and public profile will automatically follow you there. + +This SDK offers an easy way to present Gravatar user's visually in your app. + +### How to: + +We offer a variety of profile view layouts for different usecases. As an example, you can use a ```ProfileView``` to be added to your UI in this way: + +```swift +// 1. Get an instance of a ProfileService +let service = ProfileService() +// 2. Get the user's profile: +let profile = try await service.fetch(with: .email("user@email.com")) +// 3. Get the instance of a ProfileView: +let profileView = ProfileView() +// 4. Set the profile to the view: +profileView.update(with: profile) +``` +`ProfileView` will look like this: +![Profile view example](profileView.view) + +## Topics + +### Profile views + +- ``ProfileView`` +- ``ProfileSummaryView`` +- ``LargeProfileView`` +- ``LargeProfileSummaryView`` diff --git a/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileSummaryView.view@2x.png b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileSummaryView.view@2x.png new file mode 100644 index 00000000..c0a07f10 Binary files /dev/null and b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileSummaryView.view@2x.png differ diff --git a/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileSummaryView.view~dark@2x.png b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileSummaryView.view~dark@2x.png new file mode 100644 index 00000000..17c9aac7 Binary files /dev/null and b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileSummaryView.view~dark@2x.png differ diff --git a/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileView.view@2x.png b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileView.view@2x.png new file mode 100644 index 00000000..3726f20b Binary files /dev/null and b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileView.view@2x.png differ diff --git a/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileView.view~dark@2x.png b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileView.view~dark@2x.png new file mode 100644 index 00000000..d729197e Binary files /dev/null and b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileView.view~dark@2x.png differ diff --git a/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileSummaryView.view@2x.png b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileSummaryView.view@2x.png new file mode 100644 index 00000000..44cd7e5f Binary files /dev/null and b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileSummaryView.view@2x.png differ diff --git a/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileSummaryView.view~dark@2x.png b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileSummaryView.view~dark@2x.png new file mode 100644 index 00000000..78c6061b Binary files /dev/null and b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileSummaryView.view~dark@2x.png differ diff --git a/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileView.view@2x.png b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileView.view@2x.png new file mode 100644 index 00000000..0b54a8c2 Binary files /dev/null and b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileView.view@2x.png differ diff --git a/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileView.view~dark@2x.png b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileView.view~dark@2x.png new file mode 100644 index 00000000..9737963e Binary files /dev/null and b/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileView.view~dark@2x.png differ diff --git a/Sources/GravatarUI/GravatarUI.docc/Resources/gravatar-sdk@2x.png b/Sources/GravatarUI/GravatarUI.docc/Resources/gravatar-sdk@2x.png new file mode 100644 index 00000000..9faf8ac8 Binary files /dev/null and b/Sources/GravatarUI/GravatarUI.docc/Resources/gravatar-sdk@2x.png differ diff --git a/Sources/GravatarUI/ProfileView/LargeProfileSummaryView.swift b/Sources/GravatarUI/ProfileView/LargeProfileSummaryView.swift index 8b6384a6..d0fba7f1 100644 --- a/Sources/GravatarUI/ProfileView/LargeProfileSummaryView.swift +++ b/Sources/GravatarUI/ProfileView/LargeProfileSummaryView.swift @@ -1,6 +1,8 @@ import Gravatar import UIKit +/// ![](largeProfileSummaryView.view) +/// A profile view with large avatar image and sumarized information.. public class LargeProfileSummaryView: BaseProfileView { private enum Constants { static let avatarLength: CGFloat = 132.0 diff --git a/Sources/GravatarUI/ProfileView/LargeProfileView.swift b/Sources/GravatarUI/ProfileView/LargeProfileView.swift index 4b439257..900626c0 100644 --- a/Sources/GravatarUI/ProfileView/LargeProfileView.swift +++ b/Sources/GravatarUI/ProfileView/LargeProfileView.swift @@ -1,6 +1,8 @@ import Gravatar import UIKit +/// ![](largeProfileView.view) +/// A profile view with large avatar image. public class LargeProfileView: BaseProfileView { private enum Constants { static let avatarLength: CGFloat = 132.0 diff --git a/Sources/GravatarUI/ProfileView/ProfileSummaryView.swift b/Sources/GravatarUI/ProfileView/ProfileSummaryView.swift index c1fb8f8f..5e4f08ea 100644 --- a/Sources/GravatarUI/ProfileView/ProfileSummaryView.swift +++ b/Sources/GravatarUI/ProfileView/ProfileSummaryView.swift @@ -1,6 +1,8 @@ import Gravatar import UIKit +/// ![](profileSummaryView.view) +/// A smaller profile view with sumarized information public class ProfileSummaryView: BaseProfileView { private lazy var basicInfoStackView: UIStackView = { let stack = UIStackView(arrangedSubviews: [displayNameLabel, personalInfoLabel, profileButton]) diff --git a/Sources/GravatarUI/ProfileView/ProfileView.swift b/Sources/GravatarUI/ProfileView/ProfileView.swift index d7c3a931..308f7c7b 100644 --- a/Sources/GravatarUI/ProfileView/ProfileView.swift +++ b/Sources/GravatarUI/ProfileView/ProfileView.swift @@ -1,6 +1,8 @@ import Gravatar import UIKit +/// ![](profileView.view) +/// A profile view with standard layout public class ProfileView: BaseProfileView { private lazy var topStackView: UIStackView = { let stack = UIStackView(arrangedSubviews: [avatarImageView, basicInfoStackView]) diff --git a/Tests/GravatarUITests/ImageHelper.swift b/Tests/GravatarUITests/ImageHelper.swift index 55ce099e..9d73a240 100644 --- a/Tests/GravatarUITests/ImageHelper.swift +++ b/Tests/GravatarUITests/ImageHelper.swift @@ -17,6 +17,10 @@ class ImageHelper { image(named: "placeholder", type: "png")! } + static var exampleAvatarImage: UIImage { + image(named: "example_avatar", type: "png")! + } + static func dataFromImage(named: String, type: String) -> Data? { guard let url = Bundle.testsBundle.url(forResource: named, withExtension: type) else { return nil diff --git a/Tests/GravatarUITests/ProvileViewSnapshots.swift b/Tests/GravatarUITests/ProvileViewSnapshots.swift new file mode 100644 index 00000000..4229ae18 --- /dev/null +++ b/Tests/GravatarUITests/ProvileViewSnapshots.swift @@ -0,0 +1,88 @@ +import Gravatar +import GravatarUI +import SnapshotTesting +import XCTest + +final class ProfileViewSnapshots: XCTestCase { + enum Constants { + static let width: CGFloat = 320 + } + + override func setUp() async throws { + try await super.setUp() + // isRecording = true + } + + func testProfileView() throws { + for interfaceStyle in UIUserInterfaceStyle.allCases { + let profileView = ProfileView() + profileView.update(with: TestProfileCardModel.exampleModel) + let containerView = wrap(profileView) + containerView.overrideUserInterfaceStyle = interfaceStyle + let postfix = interfaceStyle == .dark ? "view-dark" : "view" + assertSnapshot(of: containerView, as: .image, named: postfix, testName: "profileView") + } + } + + func testProfileSummaryView() throws { + for interfaceStyle in UIUserInterfaceStyle.allCases { + let profileView = ProfileSummaryView() + profileView.update(with: TestProfileCardModel.exampleModel) + let containerView = wrap(profileView) + containerView.overrideUserInterfaceStyle = interfaceStyle + let postfix = interfaceStyle == .dark ? "view-dark" : "view" + assertSnapshot(of: containerView, as: .image, named: postfix, testName: "profileSummaryView") + } + } + + func testLargeProfileView() throws { + for interfaceStyle in UIUserInterfaceStyle.allCases { + let profileView = LargeProfileView() + profileView.update(with: TestProfileCardModel.exampleModel) + let containerView = wrap(profileView) + containerView.overrideUserInterfaceStyle = interfaceStyle + let postfix = interfaceStyle == .dark ? "view-dark" : "view" + assertSnapshot(of: containerView, as: .image, named: postfix, testName: "largeProfileView") + } + } + + func testLargeProfileSummaryView() throws { + for interfaceStyle in UIUserInterfaceStyle.allCases { + let profileView = LargeProfileSummaryView() + profileView.update(with: TestProfileCardModel.exampleModel) + let containerView = wrap(profileView) + containerView.overrideUserInterfaceStyle = interfaceStyle + let postfix = interfaceStyle == .dark ? "view-dark" : "view" + assertSnapshot(of: containerView, as: .image, named: postfix, testName: "largeProfileSummaryView") + } + } + + private func wrap(_ view: BaseProfileView) -> UIView { + view.avatarImageView.backgroundColor = .systemBlue + view.avatarImageView.image = ImageHelper.exampleAvatarImage + view.translatesAutoresizingMaskIntoConstraints = false + view.widthAnchor.constraint(equalToConstant: Constants.width).isActive = true + + return view.wrapInSuperView(with: Constants.width) + } +} + +extension TestProfileCardModel { + fileprivate static let exampleModel = TestProfileCardModel( + accountsList: [ + TestAccountModel(display: "Gravatar", shortname: "gravatar"), + TestAccountModel(display: "WordPress", shortname: "wordpress"), + TestAccountModel(display: "Tumblr", shortname: "tumblr"), + TestAccountModel(display: "GitHub", shortname: "github"), + ], + aboutMe: "Engineer at heart, problem-solver by nature. Passionate about innovation and pushing boundaries. Let's build something incredible together.", + displayName: "John Appleseed", + fullName: "John Appleseed", + userName: "username", + jobTitle: "Engineer", + pronouns: "he/him", + currentLocation: "Atlanta GA", + avatarIdentifier: .email("email@domain.com"), + profileURL: URL(string: "https://gravatar.com/profile") + ) +} diff --git a/Tests/GravatarUITests/Resources/example_avatar.png b/Tests/GravatarUITests/Resources/example_avatar.png new file mode 100644 index 00000000..d57a7dfe Binary files /dev/null and b/Tests/GravatarUITests/Resources/example_avatar.png differ diff --git a/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileSummaryView.view-dark.png b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileSummaryView.view-dark.png new file mode 100644 index 00000000..17c9aac7 Binary files /dev/null and b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileSummaryView.view-dark.png differ diff --git a/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileSummaryView.view.png b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileSummaryView.view.png new file mode 100644 index 00000000..c0a07f10 Binary files /dev/null and b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileSummaryView.view.png differ diff --git a/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileView.view-dark.png b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileView.view-dark.png new file mode 100644 index 00000000..d729197e Binary files /dev/null and b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileView.view-dark.png differ diff --git a/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileView.view.png b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileView.view.png new file mode 100644 index 00000000..3726f20b Binary files /dev/null and b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileView.view.png differ diff --git a/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileSummaryView.view-dark.png b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileSummaryView.view-dark.png new file mode 100644 index 00000000..78c6061b Binary files /dev/null and b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileSummaryView.view-dark.png differ diff --git a/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileSummaryView.view.png b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileSummaryView.view.png new file mode 100644 index 00000000..44cd7e5f Binary files /dev/null and b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileSummaryView.view.png differ diff --git a/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileView.view-dark.png b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileView.view-dark.png new file mode 100644 index 00000000..9737963e Binary files /dev/null and b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileView.view-dark.png differ diff --git a/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileView.view.png b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileView.view.png new file mode 100644 index 00000000..0b54a8c2 Binary files /dev/null and b/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileView.view.png differ