├── .buildkite
├── commands
│ ├── publish-pod.sh
│ ├── upload-demo-to-firebase.sh
│ └── validate-pods.sh
├── pipeline.yml
└── shared-pipeline-vars
├── .bundle
└── config
├── .configure
├── .configure-files
└── Secrets.swift.enc
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── enhancement.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── docc.yml
│ └── run-danger.yml
├── .gitignore
├── .rubocop.yml
├── .ruby-version
├── .spi.yml
├── .swiftformat
├── .swiftlint.yml
├── .travis.yml
├── CODE-OF-CONDUCT.md
├── CODINGSTYLE.md
├── CONTRIBUTING.md
├── Dangerfile
├── Demo
├── Demo
│ ├── Base.xcconfig
│ ├── Enterprise.xcconfig
│ ├── Gravatar-Demo
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ │ ├── AccentColor.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── 1024x10244.png
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ └── placeholder.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── placeholder.png
│ │ ├── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Common
│ │ │ ├── BaseFormViewController.swift
│ │ │ ├── FormFields
│ │ │ │ ├── ButtonField.swift
│ │ │ │ ├── ButtonLabelField.swift
│ │ │ │ ├── ImageFormField.swift
│ │ │ │ ├── LabelField.swift
│ │ │ │ ├── SegmentedControlField.swift
│ │ │ │ ├── SwitchField.swift
│ │ │ │ └── TextFormField.swift
│ │ │ └── SwitchWithLabel.swift
│ │ ├── DemoAvatarDownloadViewController.swift
│ │ ├── DemoBaseProfileViewController.swift
│ │ ├── DemoFetchProfileViewController.swift
│ │ ├── DemoImageCropperViewController.swift
│ │ ├── DemoProfileConfigurationViewController.swift
│ │ ├── DemoProfilePresentationStylesViewController.swift
│ │ ├── DemoProfileViewsViewController.swift
│ │ ├── DemoQuickEditorViewController.swift
│ │ ├── DemoRemoteSVGViewController.swift
│ │ ├── DemoUIImageViewExtensionViewController.swift
│ │ ├── DemoUploadImageViewController.swift
│ │ ├── Gravatar-Demo.Base.xcconfig
│ │ ├── Gravatar-Demo.Release.xcconfig
│ │ ├── Info.plist
│ │ ├── MainTableViewController.swift
│ │ ├── SceneDelegate.swift
│ │ ├── SwiftUI
│ │ │ ├── ContentView.swift
│ │ │ ├── Controls
│ │ │ │ ├── AboutInfoChecklistView.swift
│ │ │ │ ├── AvatarPickerLayoutOptions.swift
│ │ │ │ ├── QEColorSchemePickerRow.swift
│ │ │ │ ├── QEContentLayoutPickerRow.swift
│ │ │ │ ├── QEInitialPagePickerRow.swift
│ │ │ │ ├── QEScopesPickerRow.swift
│ │ │ │ └── QEVerticalStylePickerRow.swift
│ │ │ ├── DemoAvatarView.swift
│ │ │ ├── DemoProfileEditorView.swift
│ │ │ ├── DemoProfileView.swift
│ │ │ ├── ProfileViewTypePickerRow.swift
│ │ │ ├── SafariView.swift
│ │ │ ├── TestImageCropper.swift
│ │ │ └── View+Demo.swift
│ │ ├── ar.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── de.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── es.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── fr.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── he.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── id.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── it.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── ja.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── ko.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── nl.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── pt-BR.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── ru.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── sv.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── tr.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ ├── zh-Hans.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ │ └── zh-Hant.lproj
│ │ │ ├── LaunchScreen.strings
│ │ │ └── Main.strings
│ ├── Localizations
│ │ ├── ar.lproj
│ │ │ └── Localizable.strings
│ │ ├── de.lproj
│ │ │ └── Localizable.strings
│ │ ├── en.lproj
│ │ │ └── Localizable.strings
│ │ ├── es.lproj
│ │ │ └── Localizable.strings
│ │ ├── fr.lproj
│ │ │ └── Localizable.strings
│ │ ├── he.lproj
│ │ │ └── Localizable.strings
│ │ ├── id.lproj
│ │ │ └── Localizable.strings
│ │ ├── it.lproj
│ │ │ └── Localizable.strings
│ │ ├── ja.lproj
│ │ │ └── Localizable.strings
│ │ ├── ko.lproj
│ │ │ └── Localizable.strings
│ │ ├── nl.lproj
│ │ │ └── Localizable.strings
│ │ ├── pt-BR.lproj
│ │ │ └── Localizable.strings
│ │ ├── ru.lproj
│ │ │ └── Localizable.strings
│ │ ├── sv.lproj
│ │ │ └── Localizable.strings
│ │ ├── tr.lproj
│ │ │ └── Localizable.strings
│ │ ├── zh-Hans.lproj
│ │ │ └── Localizable.strings
│ │ └── zh-Hant.lproj
│ │ │ └── Localizable.strings
│ └── Secrets.tpl
├── Gravatar Demo.entitlements
└── Gravatar-Demo.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ │ └── Package.resolved
│ └── xcshareddata
│ └── xcschemes
│ └── Gravatar Demo.xcscheme
├── Documentation
└── ruby.md
├── Gemfile
├── Gemfile.lock
├── Gravatar.podspec
├── GravatarUI.podspec
├── LICENSE.md
├── Makefile
├── Package.resolved
├── Package.swift
├── README.md
├── SECURITY.md
├── Sources
├── Gravatar
│ ├── AvatarURL.swift
│ ├── Bundle+ResourceBundle.swift
│ ├── BundleInfo.swift
│ ├── Cache
│ │ └── ImageCaching.swift
│ ├── Configuration.swift
│ ├── Extensions
│ │ ├── String.swift
│ │ ├── UIImage+Additions.swift
│ │ ├── UIImage+Square.swift
│ │ └── URL.swift
│ ├── Gravatar.docc
│ │ ├── 1. GettingStarted.md
│ │ ├── 2. DownloadingAvatar.md
│ │ ├── 3. UploadingAvatar.md
│ │ ├── 4. FetchingProfile.md
│ │ ├── Gravatar.md
│ │ └── Resources
│ │ │ └── gravatar-sdk@2x.png
│ ├── Identifiers
│ │ ├── AvatarIdentifier.swift
│ │ ├── Email.swift
│ │ ├── HashID.swift
│ │ └── ProfileIdentifier.swift
│ ├── Network
│ │ ├── APIErrorPayload.swift
│ │ ├── AvatarType.swift
│ │ ├── Data+Extension.swift
│ │ ├── Error+Extension.swift
│ │ ├── Errors.swift
│ │ ├── HTTPStatus.swift
│ │ ├── HTTPURLResponse+Additions.swift
│ │ ├── ImageDownloadResult.swift
│ │ ├── Services
│ │ │ ├── AvatarService.swift
│ │ │ ├── CheckTokenAuthorizationService.swift
│ │ │ ├── HTTPClient.swift
│ │ │ ├── ImageDownloadService.swift
│ │ │ ├── ImageDownloader.swift
│ │ │ ├── ImageUploadService.swift
│ │ │ ├── ImageUploader.swift
│ │ │ ├── Model
│ │ │ │ ├── Avatar+AvatarDetails.swift
│ │ │ │ ├── AvatarDetails.swift
│ │ │ │ └── AvatarRating+Additions.swift
│ │ │ ├── ProfileFetching.swift
│ │ │ ├── ProfileService.swift
│ │ │ ├── ServiceConfig.swift
│ │ │ └── URLSessionHTTPClient.swift
│ │ └── URLSessionProtocol.swift
│ ├── OpenApi
│ │ └── Generated
│ │ │ ├── AssociatedResponse.swift
│ │ │ ├── Avatar.swift
│ │ │ ├── AvatarRating.swift
│ │ │ ├── CryptoWalletAddress.swift
│ │ │ ├── GalleryImage.swift
│ │ │ ├── Interest.swift
│ │ │ ├── Language.swift
│ │ │ ├── Link.swift
│ │ │ ├── ModelError.swift
│ │ │ ├── Profile.swift
│ │ │ ├── ProfileContactInfo.swift
│ │ │ ├── ProfilePayments.swift
│ │ │ ├── SetEmailAvatarRequest.swift
│ │ │ ├── UpdateAvatarRequest.swift
│ │ │ ├── UpdateProfileRequest.swift
│ │ │ └── VerifiedAccount.swift
│ ├── Options
│ │ ├── AvatarQueryOptions.swift
│ │ ├── AvatarSelection.swift
│ │ ├── DefaultAvatarOption.swift
│ │ ├── ImageDownloadOptions.swift
│ │ ├── ImageProcessorOption.swift
│ │ ├── ImageSize.swift
│ │ ├── ImageTransition.swift
│ │ └── Rating.swift
│ ├── ProfileURL.swift
│ ├── Resources
│ │ ├── .gitkeep
│ │ └── SDKInfo.plist
│ ├── UIImage
│ │ └── Processor
│ │ │ ├── DefaultImageProcessor.swift
│ │ │ └── ImageProcessor.swift
│ └── URLComponents+Additions.swift
├── GravatarUI
│ ├── Base
│ │ ├── Array+Additions.swift
│ │ ├── AssociatedObject.swift
│ │ ├── Box.swift
│ │ ├── IdentifiableURL.swift
│ │ ├── Result+Gravatar.swift
│ │ ├── SimpleCounter.swift
│ │ ├── UIApplication+Additions.swift
│ │ └── UIView+Additions.swift
│ ├── Bundle+ResourceBundle.swift
│ ├── Configurator
│ │ └── Configurators.swift
│ ├── DesignSystem
│ │ ├── CGFloat+DesignSystem.swift
│ │ ├── Palette.swift
│ │ ├── UIColor+DesignSystem.swift
│ │ └── UIFont+DesignSystem.swift
│ ├── Error+Extension.swift
│ ├── Exports.swift
│ ├── GravatarCompatibleUI
│ │ ├── GravatarCompatible.swift
│ │ └── UIImageView+Gravatar.swift
│ ├── GravatarUI.docc
│ │ ├── AvatarViewArticle.md
│ │ ├── GettingStarted.md
│ │ ├── GravatarOAuth.md
│ │ ├── GravatarUI.md
│ │ ├── ProfileViews.md
│ │ ├── QuickEditorArticle.md
│ │ ├── Resources
│ │ │ ├── ProfileExamples
│ │ │ │ ├── largeProfileSummaryView.view@2x.png
│ │ │ │ ├── largeProfileSummaryView.view~dark@2x.png
│ │ │ │ ├── largeProfileView.view@2x.png
│ │ │ │ ├── largeProfileView.view~dark@2x.png
│ │ │ │ ├── profileSummaryView.view@2x.png
│ │ │ │ ├── profileSummaryView.view~dark@2x.png
│ │ │ │ ├── profileView.view@2x.png
│ │ │ │ └── profileView.view~dark@2x.png
│ │ │ ├── QEExamples
│ │ │ │ ├── about-editor-intrinsic@2x.png
│ │ │ │ ├── about-editor-intrinsic~dark@2x.png
│ │ │ │ ├── about-editor-medium@2x.png
│ │ │ │ ├── about-editor-medium~dark@2x.png
│ │ │ │ ├── about-editor@2x.png
│ │ │ │ ├── about-editor~dark@2x.png
│ │ │ │ ├── avatar-and-about@2x.gif
│ │ │ │ ├── avatar-and-about~dark@2x.gif
│ │ │ │ ├── horizontal-intrinsic-height.png
│ │ │ │ ├── vertical-large.png
│ │ │ │ └── vertical-medium-expandable.png
│ │ │ ├── QuickEditor_Tutorial
│ │ │ │ ├── QuickEditor_Tutorial_01_03@2x.png
│ │ │ │ ├── QuickEditor_Tutorial_01_04@2x.png
│ │ │ │ ├── QuickEditor_Tutorial_01_05@2x.png
│ │ │ │ ├── QuickEditor_Tutorial_Header@2x.png
│ │ │ │ └── QuickEditor_Tutorial_Preview@2x.png
│ │ │ ├── gravatar-sdk@2x.png
│ │ │ ├── tutorial_01_01@2x.png
│ │ │ ├── tutorial_01_02@2x.png
│ │ │ └── tutorial_01_header@2x.png
│ │ ├── Tutorials
│ │ │ ├── ContactsList
│ │ │ │ ├── ContactsList.tutorial
│ │ │ │ ├── Tut_01.swift
│ │ │ │ ├── Tut_02.swift
│ │ │ │ ├── Tut_03.swift
│ │ │ │ ├── Tut_04.swift
│ │ │ │ ├── Tut_05.swift
│ │ │ │ ├── Tut_06.swift
│ │ │ │ └── Tut_06_comparison.swift
│ │ │ ├── QuickEditor
│ │ │ │ ├── QE_Tut_01.swift
│ │ │ │ ├── QE_Tut_02.swift
│ │ │ │ ├── QE_Tut_03.swift
│ │ │ │ ├── QE_Tut_04.swift
│ │ │ │ ├── QE_Tut_05.swift
│ │ │ │ └── QuickEditor.tutorial
│ │ │ └── Tutorials.tutorial
│ │ └── UIImageViewExtension.md
│ ├── ImageCropper
│ │ ├── CropFrameOverlayView.swift
│ │ └── ImageCropperViewController.swift
│ ├── Options
│ │ ├── ActivityIndicatorType.swift
│ │ └── ImageSettingOption.swift
│ ├── ProfileFields
│ │ ├── AboutMeBuilder.swift
│ │ ├── AccountButtonBuilder.swift
│ │ ├── DisplayNameBuilder.swift
│ │ ├── Model
│ │ │ ├── AboutMeModel.swift
│ │ │ ├── AccountModel.swift
│ │ │ ├── AvatarIdentifierProvider.swift
│ │ │ ├── ClaimProfileModel.swift
│ │ │ ├── DisplayNameModel.swift
│ │ │ ├── PersonalInfoModel.swift
│ │ │ ├── ProfileMetadataModel.swift
│ │ │ └── ProfileModel.swift
│ │ ├── PersonalInfoField.swift
│ │ └── ProfileButtonBuilder.swift
│ ├── ProfileView
│ │ ├── AccountIconWebView
│ │ │ └── RemoteSVGView.swift
│ │ ├── ActivityIndicator
│ │ │ ├── ActivityIndicator.swift
│ │ │ └── ProfileActivityIndicator.swift
│ │ ├── Avatar
│ │ │ ├── AvatarType.swift
│ │ │ └── DefaultAvatarProvider.swift
│ │ ├── BaseProfileView.swift
│ │ ├── DashedView
│ │ │ └── DashedLabel.swift
│ │ ├── LargeProfileSummaryView.swift
│ │ ├── LargeProfileView.swift
│ │ ├── Placeholder
│ │ │ ├── PlaceholderDisplayers
│ │ │ │ ├── AccountButtonsPlaceholderDisplayer.swift
│ │ │ │ ├── BackgroundColorPlaceholderDisplayer.swift
│ │ │ │ ├── LabelPlaceholderDisplayer.swift
│ │ │ │ ├── ProfileButtonPlaceholderDisplayer.swift
│ │ │ │ └── RectangularPlaceholderDisplayer.swift
│ │ │ ├── PlaceholderDisplaying.swift
│ │ │ ├── ProfileViewPlaceholderDisplaying.swift
│ │ │ └── UIView+Placeholder.swift
│ │ ├── ProfileSummaryView.swift
│ │ ├── ProfileView.swift
│ │ └── ProfileViewConfiguration.swift
│ ├── ProfileViewController
│ │ ├── ProfileViewController.swift
│ │ └── ProfileViewModel.swift
│ ├── QuickEditor
│ │ ├── AboutInfoField.swift
│ │ ├── QuickEditorConfiguration.swift
│ │ ├── QuickEditorViewController.swift
│ │ ├── SheetPresentationStyle.swift
│ │ └── UIKitSheetPresentationOnSwiftUI.swift
│ ├── Resources
│ │ ├── AccountIcons.xcassets
│ │ │ ├── Contents.json
│ │ │ ├── calendly.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── calendly.pdf
│ │ │ ├── fediverse.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── fediverse.pdf
│ │ │ ├── foursquare.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── foursquare.pdf
│ │ │ ├── github.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── github.pdf
│ │ │ ├── gravatar.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── gravatar.pdf
│ │ │ ├── instagram.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── instagram.pdf
│ │ │ ├── mastodongeneric.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── mastodongeneric.pdf
│ │ │ ├── stackoverflow.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── stackoverflow.pdf
│ │ │ ├── tiktok.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── tiktok.pdf
│ │ │ ├── tripit.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── tripit.pdf
│ │ │ ├── tumblr.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── tumblr.pdf
│ │ │ ├── twitch.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── twitch.pdf
│ │ │ ├── twitter-alt.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── twitter-alt.pdf
│ │ │ ├── vimeo.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── vimeo.pdf
│ │ │ ├── wordpress.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── wordpress.pdf
│ │ │ └── wp-link.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── LinkIcon.svg
│ │ ├── Media.xcassets
│ │ │ ├── Contents.json
│ │ │ ├── empty-profile-avatar.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── Regular-S.svg
│ │ │ ├── more-horizontal.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── more-horizontal.svg
│ │ │ ├── pencil.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── pencil.pdf
│ │ │ ├── qe-intro-empty-profile-avatar.imageset
│ │ │ │ ├── Avatar 1.svg
│ │ │ │ ├── Avatar.svg
│ │ │ │ └── Contents.json
│ │ │ └── setup-avatar-emoji.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── emoji-smile.svg
│ │ ├── ar.lproj
│ │ │ └── Localizable.strings
│ │ ├── de.lproj
│ │ │ └── Localizable.strings
│ │ ├── en.lproj
│ │ │ └── Localizable.strings
│ │ ├── es.lproj
│ │ │ └── Localizable.strings
│ │ ├── fr.lproj
│ │ │ └── Localizable.strings
│ │ ├── he.lproj
│ │ │ └── Localizable.strings
│ │ ├── id.lproj
│ │ │ └── Localizable.strings
│ │ ├── it.lproj
│ │ │ └── Localizable.strings
│ │ ├── ja.lproj
│ │ │ └── Localizable.strings
│ │ ├── ko.lproj
│ │ │ └── Localizable.strings
│ │ ├── nl.lproj
│ │ │ └── Localizable.strings
│ │ ├── pt-BR.lproj
│ │ │ └── Localizable.strings
│ │ ├── ru.lproj
│ │ │ └── Localizable.strings
│ │ ├── sv.lproj
│ │ │ └── Localizable.strings
│ │ ├── tr.lproj
│ │ │ └── Localizable.strings
│ │ ├── zh-Hans.lproj
│ │ │ └── Localizable.strings
│ │ └── zh-Hant.lproj
│ │ │ └── Localizable.strings
│ ├── SwiftUI
│ │ ├── AboutEditor
│ │ │ ├── AboutEditorView.swift
│ │ │ └── AboutInfoModel.swift
│ │ ├── AvatarPicker
│ │ │ ├── AvatarAction.swift
│ │ │ ├── AvatarGridModel.swift
│ │ │ ├── AvatarImageModel.swift
│ │ │ ├── AvatarPickerContentLayout.swift
│ │ │ ├── AvatarPickerProfileView.swift
│ │ │ ├── AvatarPickerProfileViewWrapper.swift
│ │ │ ├── AvatarPickerView.swift
│ │ │ ├── AvatarPickerViewModel.swift
│ │ │ ├── AvatarShareItem.swift
│ │ │ ├── ImageEditorView.swift
│ │ │ ├── ProfileViewPlaceholderColorManager.swift
│ │ │ ├── SystemImagePicker
│ │ │ │ ├── CameraImagePicker.swift
│ │ │ │ ├── CustomizableImageEditor.swift
│ │ │ │ ├── ImagePlaygroundModifier.swift
│ │ │ │ ├── PhotosImagePicker.swift
│ │ │ │ └── SystemImagePickerView.swift
│ │ │ └── Views
│ │ │ │ ├── AltTextEditorView.swift
│ │ │ │ ├── AvatarGrid.swift
│ │ │ │ ├── AvatarPickerAvatarView.swift
│ │ │ │ ├── CTAButtonView.swift
│ │ │ │ ├── ContentLoadingErrorView.swift
│ │ │ │ ├── DimmingActivityIndicator.swift
│ │ │ │ ├── DimmingButton.swift
│ │ │ │ ├── EmailText.swift
│ │ │ │ ├── HorizontalAvatarGrid.swift
│ │ │ │ ├── PlusButtonView.swift
│ │ │ │ └── ShareSheet.swift
│ │ ├── AvatarView.swift
│ │ ├── CachedAsyncImage.swift
│ │ ├── DismissDetectingModifier.swift
│ │ ├── GravatarNavigationModifier.swift
│ │ ├── ImageCropper.swift
│ │ ├── IntrinsicHeightView.swift
│ │ ├── LoadingIndicatorView.swift
│ │ ├── ModalPresentationModifier.swift
│ │ ├── OAuthSession
│ │ │ ├── AccessToken.swift
│ │ │ ├── Keychain.swift
│ │ │ ├── KeychainToken.swift
│ │ │ ├── OAuthSession.swift
│ │ │ ├── OldAuthenticationSession+Environment.swift
│ │ │ ├── OldAuthenticationSession.swift
│ │ │ └── ScopeLoadingErrorView.swift
│ │ ├── PreferenceKeys.swift
│ │ ├── ProfileEditor
│ │ │ ├── QuickEditor.swift
│ │ │ ├── QuickEditorNoticeView.swift
│ │ │ ├── QuickEditorScopeOption.swift
│ │ │ └── QuickEditorUpdate.swift
│ │ ├── ProfileView
│ │ │ └── ProfileViewRepresentable.swift
│ │ ├── QEDetent.swift
│ │ ├── QuickEditorModalPresentationModifier.swift
│ │ ├── SafariView.swift
│ │ ├── Toast
│ │ │ ├── Toast.swift
│ │ │ ├── ToastContainerView.swift
│ │ │ └── ToastManager.swift
│ │ └── View+Additions.swift
│ └── Utility
│ │ └── SDKLocalizedString.swift
└── TestHelpers
│ ├── Bundle+ResourceBundle.swift
│ ├── HTTPURLResponse+Extension.swift
│ ├── ImageDownloadService+Extension.swift
│ ├── ImageHelper.swift
│ ├── Resources
│ ├── Profiles
│ │ └── fullProfile.json
│ ├── avatarSelected.json
│ ├── avatarSetAltTextResponse.json
│ ├── avatarSetRatingResponse.json
│ ├── avatarUploadResponse.json
│ ├── avatarsResponse.json
│ ├── example_avatar.png
│ ├── placeholder.png
│ └── test.png
│ ├── TestImageCache.swift
│ ├── TestImageProcessor.swift
│ ├── TestURLSession.swift
│ ├── TestURLSessionError.swift
│ └── URLSessionMock.swift
├── Tests
├── GravatarTests
│ ├── AvatarIdentifierTests.swift
│ ├── AvatarServiceTests.swift
│ ├── AvatarURLTests.swift
│ ├── EmailTests.swift
│ ├── GravatarImageCacheTests.swift
│ ├── HashIDTests.swift
│ ├── ImageDownloadServiceTests.swift
│ ├── ImageSizeTests.swift
│ ├── ImageSquaringTests.swift
│ ├── ProfileIdentifierTests.swift
│ ├── ProfileServiceTests.swift
│ ├── ProfileURLTests.swift
│ ├── RenameMeTests.swift
│ ├── Resources
│ │ ├── placeholder.png
│ │ └── test.png
│ ├── UIImage+AdditionsTests.swift
│ ├── URLComponentsTests.swift
│ └── URLSessionHTTPClientTests.swift
└── GravatarUITests
│ ├── AboutEditorViewTests.swift
│ ├── AboutInfoFieldTests.swift
│ ├── AboutInfoModelTests.swift
│ ├── AboutMeBuilderTests.swift
│ ├── AccessTokenTests.swift
│ ├── AvatarGridModelTests.swift
│ ├── AvatarImageModelTests.swift
│ ├── AvatarPickerProfileViewTests.swift
│ ├── AvatarPickerViewModelTests.swift
│ ├── Bundle+ResourceBundle.swift
│ ├── CropFrameOverlayViewTests.swift
│ ├── DisplayNameBuilderTests.swift
│ ├── GravatarOptionsTests.swift
│ ├── GravatarWrapper+UIImageViewTests.swift
│ ├── KeychainTokenTests.swift
│ ├── LargeProfileSummaryViewTests.swift
│ ├── LargeProfileViewTests.swift
│ ├── OAuthSessionTests.swift
│ ├── PersonalInfoBuilderTests.swift
│ ├── ProfileButtonTests.swift
│ ├── ProfileButtonsActionsTests.swift
│ ├── ProfileConfigurationTests.swift
│ ├── ProfileSummaryViewTests.swift
│ ├── ProfileViewModelTests.swift
│ ├── ProfileViewTests.swift
│ ├── ProvileViewSnapshots.swift
│ ├── QuickEditorNoticeViewTests.swift
│ ├── Resources
│ ├── example_avatar.png
│ ├── placeholder.png
│ └── test.png
│ ├── Snapshotting+Additions.swift
│ ├── TestActivityIndicator.swift
│ ├── TestAvatar.swift
│ ├── TestImageFetcher.swift
│ ├── TestPalette.swift
│ ├── TestPlaceholderDisplayers.swift
│ ├── UIImageAdditionsTests.swift
│ └── __Snapshots__
│ ├── AboutEditorViewTests
│ ├── testAboutEditorViewAllFieldsFixedHeight.1.png
│ ├── testAboutEditorViewAllFieldsFixedHeight.2.png
│ ├── testAboutEditorViewAllFieldsIntrinsicHeight.1.png
│ ├── testAboutEditorViewAllFieldsIntrinsicHeight.2.png
│ ├── testAboutEditorViewExtraFieldsIntrinsicHeight.1.png
│ ├── testAboutEditorViewExtraFieldsIntrinsicHeight.2.png
│ ├── testAboutEditorViewOneFieldFixedHeight.1.png
│ ├── testAboutEditorViewOneFieldFixedHeight.2.png
│ ├── testAboutEditorViewPersonalFieldsIntrinsicHeight.1.png
│ ├── testAboutEditorViewPersonalFieldsIntrinsicHeight.2.png
│ ├── testAboutEditorViewProfessionalFieldsIntrinsicHeight.1.png
│ ├── testAboutEditorViewProfessionalFieldsIntrinsicHeight.2.png
│ ├── testAboutEditorWithUnsavedChanges.1.png
│ ├── testAboutEditorWithUnsavedChanges.2.png
│ ├── testAuthErrorStateAfterSave.1.png
│ ├── testAuthErrorStateAfterSave.2.png
│ ├── testLoadingErrorState.1.png
│ ├── testLoadingErrorState.2.png
│ ├── testLoadingState.1.png
│ └── testLoadingState.2.png
│ ├── AboutMeBuilderTests
│ ├── testAboutMe.testAboutMe-Dark.png
│ ├── testAboutMe.testAboutMe-Light.png
│ └── testAboutMeWithSmallWidth.1.png
│ ├── AvatarPickerProfileViewTests
│ ├── testAvatarPickerProfileView.1.png
│ ├── testAvatarPickerProfileView.2.png
│ ├── testAvatarPickerProfileViewEmpty.1.png
│ ├── testAvatarPickerProfileViewEmpty.2.png
│ ├── testAvatarPickerProfileViewWithoutLocation.1.png
│ └── testAvatarPickerProfileViewWithoutLocation.2.png
│ ├── CropFrameOverlayViewTests
│ └── testCropFrameOverlay.1.png
│ ├── DisplayNameBuilderTests
│ ├── testDisplayNameField.testDisplayNameField-Dark.png
│ ├── testDisplayNameField.testDisplayNameField-Light.png
│ ├── testDisplayNameFieldWithMissingDisplayName.testDisplayNameFieldWithMissingDisplayName-Dark.png
│ ├── testDisplayNameFieldWithMissingDisplayName.testDisplayNameFieldWithMissingDisplayName-Light.png
│ ├── testDisplayNameFieldWithMissingNames.testDisplayNameFieldWithMissingNames-Dark.png
│ ├── testDisplayNameFieldWithMissingNames.testDisplayNameFieldWithMissingNames-Light.png
│ └── testDisplayNameFieldWithSmallWidth.1.png
│ ├── LargeProfileSummaryViewTests
│ ├── testInitiallyEmptyLargeProfileSummaryView.dark.png
│ ├── testInitiallyEmptyLargeProfileSummaryView.light.png
│ ├── testLargeProfileSummaryCustomAvatarViewImageViewSubview.1.png
│ ├── testLargeProfileSummaryView.dark.png
│ ├── testLargeProfileSummaryView.light.png
│ ├── testLargeProfileSummaryViewCustomAvatarImageViewSubviewCustomStyle.1.png
│ ├── testLargeProfileSummaryViewCustomAvatarImageViewWrapper.1.png
│ ├── testLargeProfileSummaryViewCustomAvatarView.1.png
│ ├── testLargeProfileSummaryViewEmptyState.dark.png
│ ├── testLargeProfileSummaryViewEmptyState.light.png
│ ├── testLargeProfileSummaryViewEmptyStateCustomPalette.1.png
│ ├── testLargeProfileSummaryViewLoadingStateClears.light.png
│ ├── testLargeProfileSummaryViewLoadingStateClearsWhenDataIsPresent.light.png
│ ├── testLargeProfileSummaryViewLoadingStateClearsWhenEmpty.light.png
│ ├── testLargeProfileSummaryViewPlaceholderCanUpdateColors.light.png
│ ├── testLargeProfileSummaryViewPlaceholdersCanHide.light.png
│ ├── testLargeProfileSummaryViewPlaceholdersCanHideCustomPalette.1.png
│ ├── testLargeProfileSummaryViewPlaceholdersCanShow.light.png
│ └── testLargeProfileSummaryViewPlaceholdersCanShowCustomPalette.1.png
│ ├── LargeProfileViewTests
│ ├── testInitiallyEmptyLargeProfileView.Dark.png
│ ├── testInitiallyEmptyLargeProfileView.Light.png
│ ├── testLargeProfileCustomAvatarImageViewWrapper.1.png
│ ├── testLargeProfileCustomAvatarView.1.png
│ ├── testLargeProfileCustomAvatarViewImageViewSubview.1.png
│ ├── testLargeProfileView.testLargeProfileView-Dark.png
│ ├── testLargeProfileView.testLargeProfileView-Light.png
│ ├── testLargeProfileViewCustomAvatarImageViewSubviewCustomStyle.1.png
│ ├── testLargeProfileViewEmptyState.testLargeProfileView-Dark.png
│ ├── testLargeProfileViewEmptyState.testLargeProfileView-Light.png
│ ├── testLargeProfileViewEmptyStateCustomPalette.1.png
│ ├── testLargeProfileViewLoadingStateClearsWhenDataIsPresent.light.png
│ ├── testLargeProfileViewLoadingStateClearsWhenEmpty.light.png
│ ├── testLargeProfileViewPlaceholderCanUpdateColors.light.png
│ ├── testLargeProfileViewPlaceholdersCanHide.light.png
│ ├── testLargeProfileViewPlaceholdersCanHideCustomPalette.1.png
│ ├── testLargeProfileViewPlaceholdersCanShow.light.png
│ └── testLargeProfileViewPlaceholdersCanShowCustomPalette.1.png
│ ├── PersonalInfoBuilderTests
│ ├── testPersonalInfoCustom.testPersonalInfoFull-Dark.png
│ ├── testPersonalInfoCustom.testPersonalInfoFull-Light.png
│ ├── testPersonalInfoFull.testPersonalInfoFull-Dark.png
│ ├── testPersonalInfoFull.testPersonalInfoFull-Light.png
│ └── testPersonalInfoWithSmallWidth.1.png
│ ├── ProfileButtonTests
│ ├── testProfileButtonSnapshots.edit.png
│ └── testProfileButtonSnapshots.view.png
│ ├── ProfileConfigurationTests
│ └── testCustomAvatarStyle.1.png
│ ├── ProfileSummaryViewTests
│ ├── testInitiallyEmptyProfileSummaryView.dark.png
│ ├── testInitiallyEmptyProfileSummaryView.light.png
│ ├── testProfileSummaryView.dark.png
│ ├── testProfileSummaryView.light.png
│ ├── testProfileSummaryViewCustomAvatarImageViewSubviewCustomStyle.1.png
│ ├── testProfileSummaryViewCustomAvatarImageViewWrapper.1.png
│ ├── testProfileSummaryViewCustomAvatarView.1.png
│ ├── testProfileSummaryViewCustomAvatarViewImageViewSubview.1.png
│ ├── testProfileSummaryViewEmptyState.dark.png
│ ├── testProfileSummaryViewEmptyState.light.png
│ ├── testProfileSummaryViewEmptyStateCustomPalette.1.png
│ ├── testProfileSummaryViewPlaceholdersCanHide.light.png
│ ├── testProfileSummaryViewPlaceholdersCanHideCustomPalette.1.png
│ ├── testProfileSummaryViewPlaceholdersCanShow.light.png
│ ├── testProfileSummaryViewPlaceholdersCanShowCustomPalette.1.png
│ ├── testProfileViewSummaryLoadingStateClearsWhenDataIsPresent.light.png
│ ├── testProfileViewSummaryLoadingStateClearsWhenEmpty.light.png
│ └── testProfileViewSummaryPlaceholderCanUpdateColors.light.png
│ ├── ProfileViewTests
│ ├── testInitiallyEmptyProfileView.dark.png
│ ├── testInitiallyEmptyProfileView.light.png
│ ├── testProfileView.dark.png
│ ├── testProfileView.light.png
│ ├── testProfileViewCustomAvatarImageViewSubviewCustomStyle.1.png
│ ├── testProfileViewCustomAvatarImageViewWrapper.1.png
│ ├── testProfileViewCustomAvatarView.1.png
│ ├── testProfileViewCustomAvatarViewImageViewSubview.1.png
│ ├── testProfileViewEmptyState.dark.png
│ ├── testProfileViewEmptyState.light.png
│ ├── testProfileViewEmptyStateCustomPalette.1.png
│ ├── testProfileViewLoadingStateClearsWhenDataIsPresent.light.png
│ ├── testProfileViewLoadingStateClearsWhenEmpty.light.png
│ ├── testProfileViewPlaceholderCanUpdateColors.light.png
│ ├── testProfileViewPlaceholdersCanHide.light.png
│ ├── testProfileViewPlaceholdersCanHideCustomPalette.1.png
│ ├── testProfileViewPlaceholdersCanShow.light.png
│ └── testProfileViewPlaceholdersCanShowCustomPalette.1.png
│ ├── ProvileViewSnapshots
│ ├── largeProfileSummaryView.view-dark.png
│ ├── largeProfileSummaryView.view.png
│ ├── largeProfileView.view-dark.png
│ ├── largeProfileView.view.png
│ ├── profileSummaryView.view-dark.png
│ ├── profileSummaryView.view.png
│ ├── profileView.view-dark.png
│ └── profileView.view.png
│ ├── QuickEditorNoticeViewTests
│ ├── testQuickEditorNoticeView.1.png
│ ├── testQuickEditorNoticeView.2.png
│ ├── testQuickEditorNoticeViewWithError.1.png
│ ├── testQuickEditorNoticeViewWithError.2.png
│ ├── testQuickEditorNoticeViewWithoutToken.1.png
│ └── testQuickEditorNoticeViewWithoutToken.2.png
│ └── TestPlaceholderDisplayers
│ ├── testAccountButtonsPlaceholderDisplayer.placeholder-shown.png
│ ├── testBackgroundColorPlaceholderDisplayer.placeholder-hidden.png
│ ├── testBackgroundColorPlaceholderDisplayer.placeholder-shown.png
│ ├── testProfileButtonPlaceholderDisplayer.placeholder-hidden.png
│ ├── testProfileButtonPlaceholderDisplayer.placeholder-shown.png
│ ├── testRectangularColorPlaceholderDisplayer.placeholder-hidden.png
│ └── testRectangularColorPlaceholderDisplayer.placeholder-shown.png
├── access-control-modifier.swift
├── fastlane
├── Fastfile
├── example.env
├── lanes
│ └── localization.rb
└── lib
│ ├── code_signing_helpers.rb
│ ├── env_manager.rb
│ └── localizable_source.rb
├── openapi
├── GravatarOpenAPIClient
│ ├── .openapi-generator-ignore
│ └── .openapi-generator
│ │ ├── FILES
│ │ └── VERSION
├── openapi.yaml
└── templates
│ ├── model.mustache
│ ├── modelInlineEnumDeclaration.mustache
│ └── modelObject.mustache
└── version.rb
/.buildkite/commands/publish-pod.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -eu
2 |
3 | if [ $# -ne 1 ]; then
4 | echo "Error: CocoaPods publishing failed. Specify a path to a podspec."
5 | exit 1
6 | fi
7 |
8 | SLACK_WEBHOOK=$PODS_SLACK_WEBHOOK
9 | PODSPEC_PATH="$1"
10 |
11 | echo "--- :rubygems: Setting up Gems"
12 | install_gems
13 |
14 | echo "--- :cocoapods: Publishing $PODSPEC_PATH to CocoaPods CDN"
15 | publish_pod --allow-warnings --synchronous "$PODSPEC_PATH"
16 |
17 | echo "--- :slack: Notifying Slack"
18 | slack_notify_pod_published "$PODSPEC_PATH" "$SLACK_WEBHOOK"
19 |
--------------------------------------------------------------------------------
/.buildkite/commands/upload-demo-to-firebase.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -eu
2 |
3 | echo "--- :arrow_down: Downloading Prototype Build"
4 | buildkite-agent artifact download ".build/artifacts/*.ipa" . --step "build_demo"
5 | buildkite-agent artifact download ".build/artifacts/*.app.dSYM.zip" . --step "build_demo"
6 |
7 | echo "--- :rubygems: Setting up Gems"
8 | install_gems
9 |
10 | echo "--- :hammer_and_wrench: Uploading"
11 | bundle exec fastlane ios upload_demo_to_firebase
12 |
--------------------------------------------------------------------------------
/.buildkite/commands/validate-pods.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -eu
2 |
3 | echo "--- :cocoapods: Validate Gravatar.podspec"
4 | validate_podspec --allow-warnings Gravatar.podspec
5 |
6 | echo "--- :cocoapods: Validate GravatarUI.podspec"
7 | validate_podspec --allow-warnings GravatarUI.podspec
8 |
--------------------------------------------------------------------------------
/.buildkite/shared-pipeline-vars:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # This file is `source`'d before calling `buildkite-agent pipeline upload`, and can be used
4 | # to set up some variables that will be interpolated in the `.yml` pipeline before uploading it.
5 |
6 | export IMAGE_ID="xcode-16.2-macos-14.7.1-v1"
7 |
8 | export CI_TOOLKIT="automattic/a8c-ci-toolkit#3.9.1"
9 |
10 | export SWIFTFORMAT_VERSION=$( awk '/^--minversion/ { print $2 }' .swiftformat )
11 |
--------------------------------------------------------------------------------
/.bundle/config:
--------------------------------------------------------------------------------
1 | ---
2 | BUNDLE_PATH: "vendor/bundle"
3 |
--------------------------------------------------------------------------------
/.configure:
--------------------------------------------------------------------------------
1 | {
2 | "project_name": "Gravatar-SDK-iOS",
3 | "branch": "trunk",
4 | "pinned_hash": "ac80c99c7823e68dfdfa973237a0dbde652fa7b7",
5 | "files_to_copy": [
6 | {
7 | "file": "iOS/GravatarSDK/Secrets.swift",
8 | "destination": "Demo/Demo/Secrets.swift",
9 | "encrypt": true
10 | }
11 | ],
12 | "file_dependencies": [
13 |
14 | ]
15 | }
--------------------------------------------------------------------------------
/.configure-files/Secrets.swift.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/.configure-files/Secrets.swift.enc
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F41E Bug report"
3 | about: Report a bug if something isn't working as expected in Gravatar iOS SDK.
4 | title: ''
5 | labels:
6 | - 'Bug'
7 | - '[Priority] Medium'
8 | assignees: ''
9 |
10 | ---
11 |
12 | **Describe the bug**
13 |
14 |
15 | **To Reproduce**
16 | Steps to reproduce the behavior:
17 | 1.
18 |
19 | **Screenshots**
20 |
21 |
22 | **Expected behavior**
23 |
24 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/enhancement.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "✨ New Enhancement"
3 | about: Add an idea to improve an existing feature.
4 | title: ''
5 | labels: 'Enhance'
6 | assignees: ''
7 |
8 | ---
9 |
10 | Please add details of the enhancement.
11 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Closes #
2 |
3 | ### Description
4 |
5 | ### Testing Steps
6 |
--------------------------------------------------------------------------------
/.github/workflows/run-danger.yml:
--------------------------------------------------------------------------------
1 | name: ☢️ Trigger Danger On Buildkite
2 |
3 | on:
4 | pull_request:
5 | types: [labeled, unlabeled, milestoned, demilestoned, ready_for_review]
6 |
7 | jobs:
8 | dangermattic:
9 | if: ${{ (github.event.pull_request.draft == false) }}
10 | uses: Automattic/dangermattic/.github/workflows/reusable-retry-buildkite-step-on-events.yml@v1.1.2.1
11 | with:
12 | org-slug: automattic
13 | pipeline-slug: gravatar-sdk-ios
14 | retry-step-key: danger
15 | build-commit-sha: ${{ github.event.pull_request.head.sha }}
16 | secrets:
17 | buildkite-api-token: ${{ secrets.TRIGGER_BK_BUILD_TOKEN }}
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # macOS
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 | *.xccheckout
16 | *.moved-aside
17 | DerivedData
18 | *.hmap
19 | *.ipa
20 | *.dSYM*
21 |
22 | # Swift Package Manager
23 | .build
24 | .swiftpm
25 |
26 | # Bundler
27 | vendor/bundle
28 |
29 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
30 | # Carthage/Checkouts
31 |
32 | Carthage/Build
33 |
34 | # We recommend against adding the Pods directory to your .gitignore. However
35 | # you should judge for yourself, the pros and cons are mentioned at:
36 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
37 | #
38 | # Note: if you ignore the Pods directory, make sure to uncomment
39 | # `pod install` in .travis.yml
40 | #
41 | # Pods/
42 |
43 | # Fastlane
44 | fastlane/README.md
45 | fastlane/report.xml
46 | fastlane/test_output
47 |
48 | # SwiftGen (part of wpmreleasetoolkit)
49 | vendor/swiftgen
50 |
51 | # Other
52 | openapi/GravatarOpenAPIClient/Sources/
53 | Demo/Demo/Secrets.swift
54 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | AllCops:
2 | Exclude:
3 | - DerivedData/**/*
4 | - vendor/**/*
5 | - openapi-generator/**/*
6 | NewCops: enable
7 |
8 | Naming/FileName:
9 | Exclude:
10 | - "*.podspec"
11 |
12 | Metrics/BlockLength:
13 | Exclude: &fastlane
14 | - fastlane/Fastfile
15 | - fastlane/**/*.rb
16 |
17 | Metrics/MethodLength:
18 | Max: 30
19 | Exclude: *fastlane
20 |
21 | Layout/LineLength:
22 | Max: 165
23 | Exclude: *fastlane
24 |
25 | Layout/EmptyLines:
26 | Exclude: *fastlane
27 |
28 | Style/AsciiComments:
29 | Exclude: *fastlane
30 |
31 | Style/HashSyntax:
32 | EnforcedShorthandSyntax: never
33 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 3.2.2
2 |
--------------------------------------------------------------------------------
/.spi.yml:
--------------------------------------------------------------------------------
1 | # This is manifest file for the Swift Package Index for it to auto-generate and
2 | # host DocC documentation.
3 | #
4 | # For reference see https://swiftpackageindex.com/swiftpackageindex/spimanifest/documentation/spimanifest/commonusecases#Host-DocC-documentation-in-the-Swift-Package-Index
5 |
6 | version: 1
7 | builder:
8 | configs:
9 | - documentation_targets: [Gravatar, GravatarUI]
10 | platform: ios
11 |
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | swiftlint_version: 0.57.1
2 | only_rules: # Rules to run
3 | - custom_rules
4 |
5 | # If true, SwiftLint will treat all warnings as errors.
6 | strict: true
7 |
8 | included:
9 | - Sources
10 | - Tests
11 |
12 | custom_rules:
13 | no_ns_localized_string:
14 | included:
15 | - "Sources/.*\\.swift"
16 | name: "No NSLocalizedString"
17 | regex: "NSLocalizedString\\("
18 | match_kinds:
19 | - identifier
20 | message: "Use `SDKLocalizedString()` instead of `NSLocalizedString()`."
21 | severity: error
22 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # references:
2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/
3 | # * https://github.com/supermarin/xcpretty#usage
4 |
5 | osx_image: xcode7.3
6 | language: objective-c
7 | # cache: cocoapods
8 | # podfile: Example/Podfile
9 | # before_install:
10 | # - gem install cocoapods # Since Travis is not always on latest version
11 | # - pod install --project-directory=Example
12 | script:
13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/Gravatar.xcworkspace -scheme Gravatar-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty
14 | - pod lib lint
15 |
--------------------------------------------------------------------------------
/CODINGSTYLE.md:
--------------------------------------------------------------------------------
1 | ## Coding Style
2 |
3 | Make sure to read [Apple's API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/).
4 |
5 | ### Tooling
6 |
7 | We use [SwiftFormat](https://github.com/apple/swift-format) to enforce a basic swift format style.
8 |
9 | CI will fail if it finds any format issue.
10 |
11 | You can run `SwiftFormat` locally with `make lint` to get warnings, or `make swiftformat` to implement the changes automatically.
12 |
13 | ### URL, ID, API and other technical acronyms and initialisms.
14 |
15 | - Always UPPERCASED when it's part of a Type name.
16 | - Use lowercase everytime it's a prefix, and is not a type name.
17 | - Use lowercase if it's writen alone, and it's not a type name.
18 |
19 | For example:
20 |
21 | ```swift
22 | struct URLType {
23 | let url: URL
24 | let someURL: URL
25 |
26 | init(_ url: URL)
27 |
28 | func api(with userID: String) -> API
29 | func api(id: ID) -> API
30 | }
31 |
32 | let urlSomething = URLType(url)
33 | let someURL = URLType(someURL)
34 | ```
35 |
--------------------------------------------------------------------------------
/Demo/Demo/Base.xcconfig:
--------------------------------------------------------------------------------
1 | DEVELOPMENT_TEAM = PZYM8XX95Q
2 |
3 | // By default use the code sigining identity for development builds that Automatticians have access to.
4 | // This is better than using the generic "Apple Development" identity because it prevents Xcode selecting one of the other matching identities in the users' keychain.
5 | // It can happen that an Automattician has a personal development identity in the Automattic account, but that identity would not be included in the development provisioning profile, and the dev build would fail to code sign.
6 | CODE_SIGN_IDENTITY = Apple Development: Created via API (886NX39KP6)
7 |
8 | // Default the build number to 0 and delegate to build scripts for setting an appropriate number.
9 | CURRENT_PROJECT_VERSION = 0
10 |
11 | SWIFT_VERSION = 5.0
12 | SWIFT_STRICT_CONCURRENCY = complete
13 |
--------------------------------------------------------------------------------
/Demo/Demo/Enterprise.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Base.xcconfig"
2 |
3 | DEVELOPMENT_TEAM = 99KV9Z6BKV
4 |
5 | CODE_SIGN_IDENTITY = Apple Distribution
6 |
7 | // Fastlane match uses a common pattern to name provisioning profiles, which allows us use this top-level, centralized definition.
8 | // Each target + build configuration combination will interpolate its bundle id value in here.
9 | //
10 | // Note: This setting works in Xcode and it seems like xcodebuild can also resolve it.
11 | // But once we add Fastlane's build_app (gym) into the pipeline, the resulting provisioning profile value is not interpolated.
12 | // As such, we have to re-define the value explicitly in each target.
13 | //
14 | // Leaving it here for reference in case the Fastlane will be resolved...
15 | PROVISIONING_PROFILE_SPECIFIER = match InHouse $PRODUCT_BUNDLE_IDENTIFIER
16 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/Assets.xcassets/AppIcon.appiconset/1024x10244.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Demo/Demo/Gravatar-Demo/Assets.xcassets/AppIcon.appiconset/1024x10244.png
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "1024x10244.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/Assets.xcassets/placeholder.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "placeholder.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/Assets.xcassets/placeholder.imageset/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Demo/Demo/Gravatar-Demo/Assets.xcassets/placeholder.imageset/placeholder.png
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/Common/FormFields/LabelField.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | final class LabelField: FormField, @unchecked Sendable {
4 | var title: String?
5 | var subtitle: String?
6 | private let cellID = "LabelCell"
7 |
8 | init(title: String? = nil, subtitle: String? = nil) {
9 | self.title = title
10 | self.subtitle = subtitle
11 | }
12 |
13 | @MainActor
14 | override func dequeueCell(in tableView: UITableView, for indexPath: IndexPath) -> UITableViewCell {
15 | let cell = tableView.dequeueReusableCell(withIdentifier: cellID) ?? UITableViewCell(style: .subtitle, reuseIdentifier: cellID)
16 |
17 | var config = cell.defaultContentConfiguration()
18 | config.text = title
19 | config.secondaryText = subtitle
20 | cell.contentConfiguration = config
21 |
22 | return cell
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/Gravatar-Demo.Base.xcconfig:
--------------------------------------------------------------------------------
1 | PRODUCT_BUNDLE_IDENTIFIER = com.automattic.gravatar-sdk-demo-uikit
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/Gravatar-Demo.Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Gravatar-Demo.Base.xcconfig"
2 | #include "../Enterprise.xcconfig"
3 |
4 | // Declared explicitly rather than by building on top of what's defined in Base so it can be read by other tools such as Fastlane
5 | PRODUCT_BUNDLE_IDENTIFIER = com.automattic.gravatar-sdk-demo-uikit.prototype-build
6 |
7 | // Unfortunately, we need to explicitly write the bundle identifier.
8 | // See note in Enterprise.xcconfig about this.
9 | PROVISIONING_PROFILE_SPECIFIER = match InHouse com.automattic.gravatar-sdk-demo-uikit.prototype-build
10 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIApplicationSceneManifest
6 |
7 | UIApplicationSupportsMultipleScenes
8 |
9 | UISceneConfigurations
10 |
11 | UIWindowSceneSessionRoleApplication
12 |
13 |
14 | UISceneConfigurationName
15 | Default Configuration
16 | UISceneDelegateClassName
17 | $(PRODUCT_MODULE_NAME).SceneDelegate
18 | UISceneStoryboardFile
19 | Main
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/SwiftUI/Controls/AvatarPickerLayoutOptions.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import GravatarUI
3 |
4 | enum AvatarPickerLayoutOptions: String, Identifiable, CaseIterable {
5 | var id: String { rawValue }
6 |
7 | case verticalLarge = "vertical - large"
8 | case verticalExpandable = "vertical - expandable"
9 | case verticalExpandablePrioritizeScrolling = "vertical - expandable - prioritize scrolling"
10 | case horizontal = "horizontal"
11 |
12 | var contentLayout: AvatarPickerContentLayout {
13 | switch self {
14 | case .verticalLarge:
15 | .vertical(presentationStyle: .large)
16 | case .verticalExpandable:
17 | .vertical(presentationStyle: .expandableMedium())
18 | case .verticalExpandablePrioritizeScrolling:
19 | .vertical(presentationStyle: .expandableMedium(prioritizeScrollOverResize: true))
20 | case .horizontal:
21 | .horizontal()
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/SwiftUI/Controls/QEContentLayoutPickerRow.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import GravatarUI
3 |
4 | struct QEContentLayoutPickerRow: View {
5 | @Binding var contentLayoutOptions: AvatarPickerLayoutOptions
6 |
7 | var body: some View {
8 | HStack {
9 | Text("Content Layout")
10 | Spacer()
11 | Picker("Content Layout", selection: $contentLayoutOptions) {
12 | ForEach(AvatarPickerLayoutOptions.allCases) { option in
13 | Text(option.rawValue).tag(option)
14 | }
15 | }
16 | .pickerStyle(MenuPickerStyle())
17 | }
18 | }
19 | }
20 |
21 | #Preview {
22 | QEContentLayoutPickerRow(contentLayoutOptions: .constant(.verticalExpandable))
23 | }
24 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/SwiftUI/Controls/QEInitialPagePickerRow.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import GravatarUI
3 |
4 | struct QEInitialPagePickerRow: View {
5 | @Binding var initialPage: InitialPage
6 |
7 | var body: some View {
8 | HStack {
9 | Text("Initial Page")
10 | Spacer()
11 | Picker("Initial Page", selection: $initialPage) {
12 | ForEach(InitialPage.allCases) { option in
13 | Text(option.rawValue).tag(option)
14 | }
15 | }
16 | .pickerStyle(MenuPickerStyle())
17 | }
18 | }
19 | }
20 |
21 | enum InitialPage: String, CaseIterable, Identifiable {
22 | var id: String {
23 | self.rawValue
24 | }
25 |
26 | case avatarPicker = "Avatar Picker"
27 | case aboutEditor = "About Editor"
28 |
29 | func map() -> AvatarPickerAndAboutEditorConfiguration.Page {
30 | switch self {
31 | case .aboutEditor: .aboutEditor
32 | case .avatarPicker: .avatarPicker
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/SwiftUI/Controls/QEScopesPickerRow.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct QEScopesPickerRow: View {
4 | @Binding var scope: QEScope
5 |
6 | var body: some View {
7 | HStack {
8 | Text("Scope")
9 | Spacer()
10 | Picker("Scope", selection: $scope) {
11 | ForEach(QEScope.allCases, id: \.rawValue) { option in
12 | Text(option.rawValue).tag(option)
13 | }
14 | }
15 | .pickerStyle(MenuPickerStyle())
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/SwiftUI/ProfileViewTypePickerRow.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import GravatarUI
3 |
4 | struct ProfileTypePickerRow: View {
5 | enum Options: String, CaseIterable, Identifiable {
6 | var id: String {
7 | rawValue
8 | }
9 |
10 | case standard
11 | case large
12 | case summary
13 | case largeSummary
14 | }
15 |
16 | @Binding var options: Options
17 |
18 | var body: some View {
19 | HStack {
20 | Text("Style")
21 | Spacer()
22 | Picker("Style", selection: $options) {
23 | ForEach(Options.allCases) { option in
24 | Text(option.rawValue).tag(option)
25 | }
26 | }
27 | .pickerStyle(MenuPickerStyle())
28 | .onChange(of: options) { _ in
29 | }
30 | }
31 | }
32 | }
33 |
34 | #Preview {
35 | ProfileTypePickerRow(options: .constant(.standard))
36 | }
37 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/SwiftUI/SafariView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import SafariServices
3 |
4 | struct SafariView: UIViewControllerRepresentable {
5 | let url: URL
6 |
7 | func makeUIViewController(context: UIViewControllerRepresentableContext) -> SFSafariViewController {
8 | SFSafariViewController(url: url)
9 | }
10 |
11 | func updateUIViewController(_ uiViewController: SFSafariViewController, context: UIViewControllerRepresentableContext) {
12 | // No updates needed for SafariViewController
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/SwiftUI/View+Demo.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | extension View {
4 | /// Modify a view with a `ViewBuilder` closure.
5 | /// Allows us to decide which modifier to apply on runtime.
6 | func modifier(@ViewBuilder body: (Self) -> ModifiedContent) -> some View {
7 | body(self)
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/ar.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/ar.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/de.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/de.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/es.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/es.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/fr.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/fr.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/he.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/he.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/id.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/id.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/it.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/it.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/ja.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/ja.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/ko.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/ko.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/nl.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/nl.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/pt-BR.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/pt-BR.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/ru.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/ru.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/sv.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/sv.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/tr.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/tr.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/zh-Hans.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/zh-Hans.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/zh-Hant.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Gravatar-Demo/zh-Hant.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "wYS-DK-y74"; */
3 | "wYS-DK-y74.title" = "Root View Controller";
4 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/ar.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/de.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/es.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/fr.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/he.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/id.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/it.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/ja.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/ko.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/nl.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/pt-BR.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/ru.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/sv.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/tr.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/zh-Hans.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Localizations/zh-Hant.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Demo/Demo/Secrets.tpl:
--------------------------------------------------------------------------------
1 | // Secrets used in the demo app.
2 | // Do not modify the .tpl file.
3 | // After a first build of any of the demo apps, a `Secrets.swift` file will be generated.
4 | // Use the generated file to paste the secrets needed from https://gravatar.com/developers/applications
5 |
6 | struct Secrets {
7 | static let apiKey: String? = nil
8 | static let clientID: String = ""
9 | static let redirectURI: String = ""
10 | }
11 |
--------------------------------------------------------------------------------
/Demo/Gravatar Demo.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.associated-domains
6 |
7 | webcredentials:gravatar.com
8 | applinks:gravatar.com
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Demo/Gravatar-Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/Gravatar-Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/Gravatar-Demo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "originHash" : "ef380bfd827500bb40ef65e62058cb22bbebbf217402a19c327d4201d142ba21",
3 | "pins" : [
4 | {
5 | "identity" : "swift-snapshot-testing",
6 | "kind" : "remoteSourceControl",
7 | "location" : "https://github.com/pointfreeco/swift-snapshot-testing",
8 | "state" : {
9 | "revision" : "42a086182681cf661f5c47c9b7dc3931de18c6d7",
10 | "version" : "1.17.6"
11 | }
12 | },
13 | {
14 | "identity" : "swift-syntax",
15 | "kind" : "remoteSourceControl",
16 | "location" : "https://github.com/swiftlang/swift-syntax",
17 | "state" : {
18 | "revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
19 | "version" : "509.0.2"
20 | }
21 | }
22 | ],
23 | "version" : 3
24 | }
25 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source 'https://rubygems.org'
4 |
5 | gem 'cocoapods', '~> 1.14.3'
6 | gem 'danger-dangermattic', '~> 1.2.2'
7 | gem 'fastlane', '~> 2.222'
8 | gem 'fastlane-plugin-firebase_app_distribution', '~> 0.10'
9 | gem 'fastlane-plugin-wpmreleasetoolkit', '~> 13.0'
10 | gem 'rubocop', '~> 1.65'
11 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "originHash" : "ef380bfd827500bb40ef65e62058cb22bbebbf217402a19c327d4201d142ba21",
3 | "pins" : [
4 | {
5 | "identity" : "swift-snapshot-testing",
6 | "kind" : "remoteSourceControl",
7 | "location" : "https://github.com/pointfreeco/swift-snapshot-testing.git",
8 | "state" : {
9 | "revision" : "42a086182681cf661f5c47c9b7dc3931de18c6d7",
10 | "version" : "1.17.6"
11 | }
12 | },
13 | {
14 | "identity" : "swift-syntax",
15 | "kind" : "remoteSourceControl",
16 | "location" : "https://github.com/swiftlang/swift-syntax",
17 | "state" : {
18 | "revision" : "303e5c5c36d6a558407d364878df131c3546fad8",
19 | "version" : "510.0.2"
20 | }
21 | }
22 | ],
23 | "version" : 3
24 | }
25 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Reporting a Vulnerability
4 |
5 | The Gravatar team takes security bugs in Gravatar seriously. We appreciate your efforts to responsibly disclose your findings.
6 |
7 | To report a security issue, please use [HackerOne](https://hackerone.com/automattic).
8 |
9 | Report security bugs in third-party modules to the person or team maintaining the module.
10 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Bundle+ResourceBundle.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | #if !SWIFT_PACKAGE
4 | private class BundleFinder: NSObject {}
5 | extension Bundle {
6 | static var module: Bundle {
7 | let defaultBundle = Bundle(for: BundleFinder.self)
8 | // If installed with CocoaPods, resources will be in Gravatar.bundle
9 | // The name of the bundle "Gravatar.bundle" (without the .bundle file extension)
10 | // needs to match the key in the respective Gravatar.podspec:
11 | // `s.resource_bundles = { 'Gravatar' => ['Sources/Gravatar/Resources/*.plist'] }`
12 | if let bundleURL = defaultBundle.resourceURL,
13 | let resourceBundle = Bundle(url: bundleURL.appendingPathComponent("Gravatar.bundle"))
14 | {
15 | return resourceBundle
16 | }
17 | // Otherwise, the default bundle is used for resources
18 | return defaultBundle
19 | }
20 | }
21 | #endif
22 |
--------------------------------------------------------------------------------
/Sources/Gravatar/BundleInfo.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | package enum BundleInfo {
4 | package static var sdkVersion: String? {
5 | getInfoValue(forKey: "CFBundleShortVersionString") as? String
6 | }
7 |
8 | package static var appName: String? {
9 | Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String
10 | }
11 |
12 | private static func getInfoValue(forKey key: String) -> Any? {
13 | // Access the SDKInfo.plist using Bundle.module
14 | guard let url = Bundle.module.url(forResource: "SDKInfo", withExtension: "plist"),
15 | let data = try? Data(contentsOf: url),
16 | let plist = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: Any]
17 | else {
18 | return nil
19 | }
20 | return plist[key]
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Extensions/String.swift:
--------------------------------------------------------------------------------
1 | import CryptoKit
2 | import Foundation
3 |
4 | extension String {
5 | func hashed() -> String {
6 | self.sanitized.sha256()
7 | }
8 |
9 | private func sha256() -> String {
10 | let hashed = SHA256.hash(data: Data(self.utf8))
11 | let hashString = hashed.compactMap { String(format: "%02x", $0) }.joined()
12 | return hashString
13 | }
14 | }
15 |
16 | extension String {
17 | var sanitized: String {
18 | self.lowercased()
19 | .trimmingCharacters(in: .whitespaces)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Extensions/UIImage+Additions.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension UIImage {
4 | /// Saves image into the temp directory as a jpeg file.
5 | /// - Returns: The URL of the file.
6 | package func saveToFile() throws -> URL? {
7 | guard let imageData = jpegData(compressionQuality: 1) else { return nil }
8 | let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("image.jpg")
9 | try imageData.write(to: fileURL)
10 | return fileURL
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Gravatar.docc/3. UploadingAvatar.md:
--------------------------------------------------------------------------------
1 | # Uploading an Avatar
2 |
3 | Let a user to update their avatar.
4 |
5 | You can provide a way to upload a new avatar for your users who have a Gravatar account.
6 |
7 | At the moment, Gravatar uses WordPress.com OAuth2 access token. Thus, you need a WordPress.com access token to update a user's avatar. Check out [the documentation](https://developer.wordpress.com/docs/oauth2/) to find more about how to get consent from the user and how to retrieve an access token.
8 |
9 | Use ``AvatarService`` to upload an avatar.
10 |
11 | ```swift
12 | import Gravatar
13 |
14 | // [...]
15 |
16 | let service = AvatarService()
17 | let image: UIImage = // image of choice from the user
18 | let accessToken = // WordPress.com OAuth2 access token
19 | do {
20 | try await service.upload(image, email: Email("email@domain.com"), accessToken: accessToken)
21 | } catch {
22 | // handle error
23 | }
24 |
25 | ``
26 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Gravatar.docc/Gravatar.md:
--------------------------------------------------------------------------------
1 | # ``Gravatar``
2 |
3 | Gravatar iOS SDK
4 |
5 | @Metadata {
6 | @PageImage(
7 | purpose: icon,
8 | source: "gravatar-sdk"
9 | )
10 | }
11 |
12 | ## Overview
13 |
14 | An “avatar” is an image that represents you online—a little picture that appears next to your name when you interact with websites.
15 |
16 | 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.
17 |
18 | This SDK will allow you to easily implement the Gravatar services in your project.
19 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Gravatar.docc/Resources/gravatar-sdk@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/Gravatar/Gravatar.docc/Resources/gravatar-sdk@2x.png
--------------------------------------------------------------------------------
/Sources/Gravatar/Identifiers/Email.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// Represents a Gravatar account email address
4 | public struct Email: Equatable, Sendable {
5 | let string: String
6 |
7 | var hashID: HashID {
8 | HashID(email: self)
9 | }
10 |
11 | /// Initializes a new Email object, representing a Gravatar account email address
12 | /// - Parameter string: The Gravatar account email address`
13 | public init(_ string: String) {
14 | self.string = string.sanitized
15 | }
16 | }
17 |
18 | extension Email: Identifiable {
19 | /// The string that the API expects when specifying a Gravatar type, such as an avatar or profile
20 | public var id: String {
21 | self.hashID.id
22 | }
23 | }
24 |
25 | extension Email: RawRepresentable {
26 | public init?(rawValue: String) {
27 | self.init(rawValue)
28 | }
29 |
30 | public var rawValue: String {
31 | string
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Identifiers/HashID.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// A type that provides a hash that represents a gravatar profile
4 | public struct HashID: Equatable, Sendable {
5 | let string: String
6 |
7 | /// Initializes a new `HashID` object, reprensenting the gravatar hash of the Gravatar email address
8 | /// - Parameter string: The gravatar hash of the Gravatar email address
9 | public init(_ string: String) {
10 | self.string = string
11 | }
12 |
13 | /// Initializes a new `HashID` object, reprensenting the gravatar hash of the Gravatar email address
14 | /// - Parameter email: an `Email` containing the Gravatar email address
15 | public init(email: Email) {
16 | self.init(email.string.hashed())
17 | }
18 | }
19 |
20 | extension HashID: Identifiable {
21 | /// The string that the API expects when specifying a Gravatar type, such as an avatar or profile
22 | public var id: String {
23 | string
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/APIErrorPayload.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// Error payload for the REST API calls.
4 | public protocol APIErrorPayload: Sendable {
5 | /// A business error code that identifies this error. (This is not the HTTP status code.)
6 | var code: String? { get }
7 | /// Error message that comes from the REST API.
8 | var message: String? { get }
9 | }
10 |
11 | extension ModelError: APIErrorPayload {
12 | public var message: String? {
13 | error
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/AvatarType.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public protocol AvatarType: Sendable {
4 | var url: String { get }
5 | var id: String { get }
6 | }
7 |
8 | extension Avatar: AvatarType {
9 | public var id: String {
10 | imageId
11 | }
12 |
13 | public var url: String {
14 | imageUrl
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/Data+Extension.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension Data {
4 | func decode(
5 | dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601,
6 | keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys
7 | ) throws -> T {
8 | let decoder = JSONDecoder()
9 | decoder.dateDecodingStrategy = dateDecodingStrategy
10 | decoder.keyDecodingStrategy = keyDecodingStrategy
11 | return try decoder.decode(T.self, from: self)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/Error+Extension.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension Error {
4 | func apiError() -> APIError {
5 | switch self {
6 | case let error as HTTPClientError:
7 | APIError.responseError(reason: error.map())
8 | case let error as DecodingError:
9 | APIError.decodingError(error)
10 | case let error:
11 | APIError.responseError(reason: .unexpected(error))
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/HTTPStatus.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// Some HTTP status codes we handle
4 | package enum HTTPStatus: Int {
5 | case badRequest = 400
6 | case unauthorized = 401
7 | case forbidden = 403
8 | case notFound = 404
9 | case payloadTooLarge = 413
10 | }
11 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/HTTPURLResponse+Additions.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension HTTPURLResponse {
4 | /// Whether the status code is an error of any kind (`4xx` or `5xx`)
5 | package var isError: Bool {
6 | isClientError || isServerError
7 | }
8 |
9 | /// Whether the status code is a client error code: `4xx`
10 | package var isClientError: Bool {
11 | statusCode >= 400 && statusCode < 500
12 | }
13 |
14 | /// Whether the status code is a client error code: `5xx`
15 | package var isServerError: Bool {
16 | statusCode >= 500 && statusCode < 600
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/ImageDownloadResult.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 |
4 | /// Represents the result of a Gravatar image download task.
5 | public struct ImageDownloadResult: Sendable {
6 | public init(image: UIImage, sourceURL: URL) {
7 | self.image = image
8 | self.sourceURL = sourceURL
9 | }
10 |
11 | /// Gets the image of this result.
12 | public let image: UIImage
13 |
14 | /// The `URL` which this result is related to.
15 | public let sourceURL: URL
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/Services/ImageDownloader.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 |
4 | /// Represents a type which can be used by Gravatar to fetch images.
5 | public protocol ImageDownloader: Sendable {
6 | /// Fetches an image from the given `URL`, and delivers the image asynchronously. Throws `ImageFetchingError`.
7 | /// - Parameters:
8 | /// - url: The URL from where to download the image.
9 | /// - forceRefresh: Force the image to be downloaded, ignoring the cache.
10 | /// - processingMethod: Method to use for processing the downloaded `Data`.
11 | /// - Returns: An asynchronously-delivered Result type containing the image and its URL.
12 | func fetchImage(
13 | with url: URL,
14 | forceRefresh: Bool,
15 | processingMethod: ImageProcessingMethod
16 | ) async throws -> ImageDownloadResult
17 | }
18 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/Services/ImageUploader.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | typealias HTTPHeaderField = (name: String, value: String)
4 |
5 | /// Represents a type which can be used by Gravatar to upload an image to Gravatar.
6 | protocol ImageUploader: Sendable {
7 | /// Uploads an image to be used as the user's Gravatar profile image, and returns the `URLResponse` of the network tasks asynchronously. Throws
8 | /// `ImageUploadError`.
9 | /// - Parameters:
10 | /// - image: The image to be uploaded.
11 | /// - email: The user email account.
12 | /// - accessToken: The authentication token for the user.
13 | /// - avatarSelection: How to handle avatar selection after uploading a new avatar
14 | /// - additionalHTTPHeaders: Additional headers to add.
15 | /// - Returns: An asynchronously-delivered `URLResponse` instance, containing the response of the upload network task.
16 | @discardableResult
17 | func uploadImage(
18 | _ image: UIImage,
19 | accessToken: String,
20 | avatarSelection: AvatarSelection,
21 | additionalHTTPHeaders: [HTTPHeaderField]?
22 | ) async throws -> (data: Data, response: HTTPURLResponse)
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/Services/Model/Avatar+AvatarDetails.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// To avoid name conflicts between `Rating` and `Avatar.Rating`
4 | package typealias ImageRating = Rating
5 |
6 | extension Avatar: AvatarDetails {
7 | package var imageID: ImageID {
8 | imageId
9 | }
10 |
11 | package var imageURL: String {
12 | imageUrl
13 | }
14 |
15 | package var imageRating: ImageRating {
16 | switch rating {
17 | case .g:
18 | ImageRating.general
19 | case .pg:
20 | ImageRating.parentalGuidance
21 | case .r:
22 | ImageRating.restricted
23 | case .x:
24 | ImageRating.x
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/Services/Model/AvatarDetails.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public typealias ImageID = String
4 |
5 | public protocol AvatarDetails: Sendable {
6 | /// Unique identifier for the image.
7 | var imageID: ImageID { get }
8 | /// Image URL
9 | var imageURL: String { get }
10 | /// Rating associated with the image.
11 | var imageRating: Rating { get }
12 | /// Alternative text description of the image.
13 | var altText: String { get }
14 | /// Whether the image is currently selected as the provided selected email's avatar.
15 | var selected: Bool? { get }
16 | /// Date and time when the image was last updated.
17 | var updatedDate: Date { get }
18 | }
19 |
20 | extension AvatarDetails {
21 | package func url(withSize size: String) -> String {
22 | if let newURL = URLComponents(string: imageURL)?.replacingQueryItem(name: "size", value: size).string {
23 | return newURL
24 | }
25 | return imageURL
26 | }
27 |
28 | package var isSelected: Bool {
29 | selected ?? false
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/Services/Model/AvatarRating+Additions.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension AvatarRating {
4 | package func toRating() -> Rating {
5 | switch self {
6 | case .g:
7 | .general
8 | case .pg:
9 | .parentalGuidance
10 | case .r:
11 | .restricted
12 | case .x:
13 | .x
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/Services/ProfileFetching.swift:
--------------------------------------------------------------------------------
1 | protocol ProfileFetching {
2 | /// Fetches a Gravatar user's profile information, and delivers the user profile asynchronously.
3 | /// - Parameter profileID: a ProfileIdentifier
4 | /// - Returns: An asynchronously-delivered user profile.
5 | func fetch(with profileID: ProfileIdentifier) async throws -> Profile
6 | }
7 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/Services/ServiceConfig.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | enum APIConfig {
4 | private static let baseURLString = "https://api.gravatar.com/"
5 | static let baseURL = URL(string: baseURLString)!
6 | static let baseURLComponents = URLComponents(string: baseURLString)!
7 | }
8 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Network/URLSessionProtocol.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// Protocol for dependency injection purposes. [URLSession] conforms to this protocol.
4 | ///
5 | /// [URLSession]: https://developer.apple.com/documentation/foundation/urlsession
6 | public protocol URLSessionProtocol: Sendable {
7 | func data(for request: URLRequest) async throws -> (Data, URLResponse)
8 |
9 | func upload(for request: URLRequest, from bodyData: Data) async throws -> (Data, URLResponse)
10 | }
11 |
12 | extension URLSession: URLSessionProtocol {}
13 |
--------------------------------------------------------------------------------
/Sources/Gravatar/OpenApi/Generated/AssociatedResponse.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct AssociatedResponse: Codable, Hashable, Sendable {
4 | /// Whether the entity is associated with the account.
5 | private(set) var associated: Bool
6 |
7 | init(associated: Bool) {
8 | self.associated = associated
9 | }
10 |
11 | enum CodingKeys: String, CodingKey, CaseIterable {
12 | case associated
13 | }
14 |
15 | // Encodable protocol methods
16 |
17 | func encode(to encoder: Encoder) throws {
18 | var container = encoder.container(keyedBy: CodingKeys.self)
19 | try container.encode(associated, forKey: .associated)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Gravatar/OpenApi/Generated/AvatarRating.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// Rating associated with the image.
4 | ///
5 | enum AvatarRating: String, Codable, CaseIterable {
6 | case g = "G"
7 | case pg = "PG"
8 | case r = "R"
9 | case x = "X"
10 | }
11 |
--------------------------------------------------------------------------------
/Sources/Gravatar/OpenApi/Generated/CryptoWalletAddress.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// A crypto currency wallet address the user accepts.
4 | ///
5 | public struct CryptoWalletAddress: Codable, Hashable, Sendable {
6 | /// The label for the crypto currency.
7 | public private(set) var label: String
8 | /// The wallet address for the crypto currency.
9 | public private(set) var address: String
10 |
11 | init(label: String, address: String) {
12 | self.label = label
13 | self.address = address
14 | }
15 |
16 | enum CodingKeys: String, CodingKey, CaseIterable {
17 | case label
18 | case address
19 | }
20 |
21 | // Encodable protocol methods
22 |
23 | public func encode(to encoder: Encoder) throws {
24 | var container = encoder.container(keyedBy: CodingKeys.self)
25 | try container.encode(label, forKey: .label)
26 | try container.encode(address, forKey: .address)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/Gravatar/OpenApi/Generated/GalleryImage.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// A gallery image a user has uploaded.
4 | ///
5 | public struct GalleryImage: Codable, Hashable, Sendable {
6 | /// The URL to the image.
7 | public private(set) var url: String
8 | /// The image alt text.
9 | public private(set) var altText: String?
10 |
11 | init(url: String, altText: String? = nil) {
12 | self.url = url
13 | self.altText = altText
14 | }
15 |
16 | enum CodingKeys: String, CodingKey, CaseIterable {
17 | case url
18 | case altText = "alt_text"
19 | }
20 |
21 | // Encodable protocol methods
22 |
23 | public func encode(to encoder: Encoder) throws {
24 | var container = encoder.container(keyedBy: CodingKeys.self)
25 | try container.encode(url, forKey: .url)
26 | try container.encodeIfPresent(altText, forKey: .altText)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/Gravatar/OpenApi/Generated/Interest.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// An interest the user has added to their profile.
4 | ///
5 | public struct Interest: Codable, Hashable, Sendable {
6 | /// The unique identifier for the interest.
7 | public private(set) var id: Int
8 | /// The name of the interest as originally defined (most often in English).
9 | public private(set) var name: String
10 |
11 | init(id: Int, name: String) {
12 | self.id = id
13 | self.name = name
14 | }
15 |
16 | enum CodingKeys: String, CodingKey, CaseIterable {
17 | case id
18 | case name
19 | }
20 |
21 | // Encodable protocol methods
22 |
23 | public func encode(to encoder: Encoder) throws {
24 | var container = encoder.container(keyedBy: CodingKeys.self)
25 | try container.encode(id, forKey: .id)
26 | try container.encode(name, forKey: .name)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/Gravatar/OpenApi/Generated/Link.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// A link the user has added to their profile.
4 | ///
5 | public struct Link: Codable, Hashable, Sendable {
6 | /// The label for the link.
7 | public private(set) var label: String
8 | /// The URL to the link.
9 | public private(set) var url: String
10 |
11 | init(label: String, url: String) {
12 | self.label = label
13 | self.url = url
14 | }
15 |
16 | enum CodingKeys: String, CodingKey, CaseIterable {
17 | case label
18 | case url
19 | }
20 |
21 | // Encodable protocol methods
22 |
23 | public func encode(to encoder: Encoder) throws {
24 | var container = encoder.container(keyedBy: CodingKeys.self)
25 | try container.encode(label, forKey: .label)
26 | try container.encode(url, forKey: .url)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/Gravatar/OpenApi/Generated/ModelError.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// An error response from the API.
4 | ///
5 | struct ModelError: Codable, Hashable, Sendable {
6 | /// The error message
7 | private(set) var error: String
8 | /// The error code for the error message
9 | private(set) var code: String?
10 |
11 | init(error: String, code: String? = nil) {
12 | self.error = error
13 | self.code = code
14 | }
15 |
16 | enum CodingKeys: String, CodingKey, CaseIterable {
17 | case error
18 | case code
19 | }
20 |
21 | // Encodable protocol methods
22 |
23 | func encode(to encoder: Encoder) throws {
24 | var container = encoder.container(keyedBy: CodingKeys.self)
25 | try container.encode(error, forKey: .error)
26 | try container.encodeIfPresent(code, forKey: .code)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/Gravatar/OpenApi/Generated/ProfilePayments.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// The user's public payment information. This is only provided in authenticated API requests.
4 | ///
5 | public struct ProfilePayments: Codable, Hashable, Sendable {
6 | /// A list of payment URLs the user has added to their profile.
7 | public private(set) var links: [Link]
8 | /// A list of crypto currencies the user accepts.
9 | public private(set) var cryptoWallets: [CryptoWalletAddress]
10 |
11 | init(links: [Link], cryptoWallets: [CryptoWalletAddress]) {
12 | self.links = links
13 | self.cryptoWallets = cryptoWallets
14 | }
15 |
16 | enum CodingKeys: String, CodingKey, CaseIterable {
17 | case links
18 | case cryptoWallets = "crypto_wallets"
19 | }
20 |
21 | // Encodable protocol methods
22 |
23 | public func encode(to encoder: Encoder) throws {
24 | var container = encoder.container(keyedBy: CodingKeys.self)
25 | try container.encode(links, forKey: .links)
26 | try container.encode(cryptoWallets, forKey: .cryptoWallets)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/Gravatar/OpenApi/Generated/SetEmailAvatarRequest.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct SetEmailAvatarRequest: Codable, Hashable, Sendable {
4 | /// The email SHA256 hash to set the avatar for.
5 | private(set) var emailHash: String
6 |
7 | init(emailHash: String) {
8 | self.emailHash = emailHash
9 | }
10 |
11 | enum CodingKeys: String, CodingKey, CaseIterable {
12 | case emailHash = "email_hash"
13 | }
14 |
15 | // Encodable protocol methods
16 |
17 | func encode(to encoder: Encoder) throws {
18 | var container = encoder.container(keyedBy: CodingKeys.self)
19 | try container.encode(emailHash, forKey: .emailHash)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Gravatar/OpenApi/Generated/UpdateAvatarRequest.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// The avatar data to update. Partial updates are supported, so only the provided fields will be updated.
4 | ///
5 | struct UpdateAvatarRequest: Codable, Hashable, Sendable {
6 | /// Rating associated with the image.
7 | private(set) var rating: AvatarRating?
8 | /// Alternative text description of the image.
9 | private(set) var altText: String?
10 |
11 | init(rating: AvatarRating? = nil, altText: String? = nil) {
12 | self.rating = rating
13 | self.altText = altText
14 | }
15 |
16 | enum CodingKeys: String, CodingKey, CaseIterable {
17 | case rating
18 | case altText = "alt_text"
19 | }
20 |
21 | // Encodable protocol methods
22 |
23 | func encode(to encoder: Encoder) throws {
24 | var container = encoder.container(keyedBy: CodingKeys.self)
25 | try container.encodeIfPresent(rating, forKey: .rating)
26 | try container.encodeIfPresent(altText, forKey: .altText)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Options/AvatarSelection.swift:
--------------------------------------------------------------------------------
1 | /// Defines how to handle avatar selection after uploading a new avatar
2 | public enum AvatarSelection: Equatable, Sendable {
3 | case preserveSelection
4 | case selectUploadedImage(for: Email)
5 | case selectUploadedImageIfNoneSelected(for: Email)
6 |
7 | public static func allCases(for email: Email) -> [AvatarSelection] {
8 | [
9 | .preserveSelection,
10 | .selectUploadedImage(for: email),
11 | .selectUploadedImageIfNoneSelected(for: email),
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Options/ImageProcessorOption.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 |
4 | /// Enum defining methods for processing and transforming the image data into a UIImage instance.
5 | ///
6 | /// Each case represents a specific processing or transformation method that will be applied to the image data.
7 | public enum ImageProcessingMethod: Sendable {
8 | /// Apply a custom processor to the image data.
9 | /// - Parameter processor: An instance of a type conforming to `ImageProcessor`.
10 | case custom(processor: ImageProcessor)
11 |
12 | /// A processing method which will directly transform the `Data` to an `UIImage` and return it.
13 | ///
14 | /// - Parameter scaleFactor: The scale factor to use to create the `UIImage`. If nil, UITraitCollection's displayScale is used.
15 | case common(scaleFactor: CGFloat = UITraitCollection.current.displayScale)
16 | }
17 |
18 | extension ImageProcessingMethod {
19 | var processor: ImageProcessor {
20 | switch self {
21 | case .common(let scaleFactor):
22 | DefaultImageProcessor(scaleFactor: scaleFactor)
23 | case .custom(let processor):
24 | processor
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Options/ImageSize.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | /// The size of the image to be requested.
4 | ///
5 | /// Gravatar images are always square. Providing the desired square side length is sufficient.
6 | /// Note that many users have lower resolution images. Requesting larger sizes may result in low-quality images.
7 | /// For more info, see [Gravatar Image docs](https://docs.gravatar.com/general/images/#size)
8 | public enum ImageSize {
9 | /// Points are preferred when working with UI components, such as UIImageView.
10 | /// - As an example: If the size of the Image View is 40x40, you can request the image size with`.points(40)`.
11 | /// The suitable pixel value is calculated internally, according to the screen of the user's device.
12 | case points(CGFloat)
13 | /// The returned image's size in pixels will be of the exact value passed here.
14 | case pixels(Int)
15 | }
16 |
17 | extension ImageSize {
18 | func pixels(scaleFactor: CGFloat) -> Int {
19 | switch self {
20 | case .pixels(let pixels):
21 | pixels
22 | case .points(let points):
23 | Int(points * scaleFactor)
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Options/ImageTransition.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public enum ImageTransition: Sendable {
4 | /// No animation transition.
5 | case none
6 | /// Fade in the loaded image in a given duration.
7 | case fade(TimeInterval)
8 | }
9 |
10 | extension ImageTransition: Equatable {}
11 |
--------------------------------------------------------------------------------
/Sources/Gravatar/ProfileURL.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public struct ProfileURL {
4 | public let url: URL
5 | public let hash: String
6 | public var avatarURL: AvatarURL? {
7 | AvatarURL(with: .hashID(self.hash))
8 | }
9 |
10 | static let baseURL: URL? = {
11 | guard
12 | let baseURL = URL(string: .baseURL),
13 | let components = URLComponents(url: baseURL, resolvingAgainstBaseURL: false)
14 | else {
15 | return nil
16 | }
17 | return components.url
18 | }()
19 |
20 | public init?(with profileID: ProfileIdentifier) {
21 | guard let url = Self.baseURL?.appending(pathComponent: profileID.id) else {
22 | return nil
23 | }
24 |
25 | self.url = url
26 | self.hash = profileID.id
27 | }
28 | }
29 |
30 | extension String {
31 | fileprivate static let baseURL = "https://gravatar.com/"
32 | }
33 |
--------------------------------------------------------------------------------
/Sources/Gravatar/Resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/Gravatar/Resources/.gitkeep
--------------------------------------------------------------------------------
/Sources/Gravatar/Resources/SDKInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleShortVersionString
6 | 3.4.0-rc.1
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Sources/Gravatar/UIImage/Processor/DefaultImageProcessor.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// The default processor. It applies the scale factor on the given image data and converts it into an image.
4 | struct DefaultImageProcessor: ImageProcessor, Sendable {
5 | public let scaleFactor: CGFloat
6 |
7 | public func process(_ data: Data) -> UIImage? {
8 | UIImage(data: data, scale: scaleFactor)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Sources/Gravatar/UIImage/Processor/ImageProcessor.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 |
4 | /// Processor to apply to the downloaded image data.
5 | public protocol ImageProcessor: Sendable {
6 | func process(_ data: Data) -> UIImage?
7 | }
8 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Base/Array+Additions.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension Array {
4 | subscript(safe index: Int) -> Element? {
5 | guard index >= 0 && index < count else { return nil }
6 | return self[index]
7 | }
8 | }
9 |
10 | extension [Bool] {
11 | var hasMoreThanOneTrue: Bool {
12 | count { $0 } > 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Base/AssociatedObject.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | func getAssociatedObject(_ object: Any, _ key: UnsafeRawPointer) -> T? {
4 | if #available(iOS 14, *) { // swift 5.3 fixed this issue (https://github.com/apple/swift/issues/46456)
5 | objc_getAssociatedObject(object, key) as? T
6 | } else {
7 | objc_getAssociatedObject(object, key) as AnyObject as? T
8 | }
9 | }
10 |
11 | func setRetainedAssociatedObject(_ object: Any, _ key: UnsafeRawPointer, _ value: some Any) {
12 | objc_setAssociatedObject(object, key, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Base/Box.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | class Box {
4 | var value: T
5 |
6 | init(_ value: T) {
7 | self.value = value
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Base/IdentifiableURL.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct IdentifiableURL: Identifiable {
4 | let url: URL
5 |
6 | init?(url: URL?) { // for convenience
7 | guard let url else { return nil }
8 | self.url = url
9 | }
10 |
11 | public var id: String {
12 | url.absoluteString
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Base/SimpleCounter.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | @MainActor
4 | enum SimpleCounter {
5 | private(set) static var current: UInt = 0
6 | static func next() -> UInt {
7 | current += 1
8 | return current
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Base/UIApplication+Additions.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension UIApplication {
4 | func dismissKeyboard() {
5 | sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Base/UIView+Additions.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension UIView {
4 | static func spacer() -> UIView {
5 | let spacer = UIView()
6 | spacer.translatesAutoresizingMaskIntoConstraints = false
7 | spacer.setContentHuggingPriority(.defaultLow, for: .vertical)
8 | spacer.setContentHuggingPriority(.defaultLow, for: .horizontal)
9 | return spacer
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Bundle+ResourceBundle.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | #if !SWIFT_PACKAGE
4 | private class BundleFinder: NSObject {}
5 | extension Bundle {
6 | static var module: Bundle {
7 | let defaultBundle = Bundle(for: BundleFinder.self)
8 | // If installed with CocoaPods, resources will be in GravatarUI.bundle
9 | if let bundleURL = defaultBundle.resourceURL,
10 | let resourceBundle = Bundle(url: bundleURL.appendingPathComponent("GravatarUI.bundle"))
11 | {
12 | return resourceBundle
13 | }
14 | // Otherwise, the default bundle is used for resources
15 | return defaultBundle
16 | }
17 | }
18 | #endif
19 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/DesignSystem/CGFloat+DesignSystem.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension CGFloat {
4 | enum DS {
5 | enum Padding {
6 | public static let half: CGFloat = 4
7 | public static let single: CGFloat = 8
8 | public static let split: CGFloat = 12
9 | public static let double: CGFloat = 16
10 | public static let medium: CGFloat = 24
11 | public static let large: CGFloat = 32
12 | public static let max: CGFloat = 48
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Error+Extension.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Gravatar
3 |
4 | extension Error {
5 | func map() -> ImageFetchingError {
6 | switch self {
7 | case let error as ImageFetchingError:
8 | error
9 | case let error:
10 | ImageFetchingError.responseError(reason: .unexpected(error))
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Exports.swift:
--------------------------------------------------------------------------------
1 | @_exported import Gravatar
2 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarCompatibleUI/GravatarCompatible.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 |
4 | @MainActor
5 | /// Wrapper for `GravatarCompatible` types.
6 | public struct GravatarWrapper {
7 | public let component: Component
8 | public init(_ component: Component) {
9 | self.component = component
10 | }
11 | }
12 |
13 | public protocol GravatarCompatible: AnyObject {}
14 |
15 | @MainActor
16 | /// Provides namespacing for the Gravatar functionality.
17 | extension GravatarCompatible {
18 | /// Returns a wrapper that provides Gravatar's convenience methods and properties.
19 | public var gravatar: GravatarWrapper {
20 | get { GravatarWrapper(self) }
21 | set {}
22 | }
23 | }
24 |
25 | extension UIImageView: GravatarCompatible {}
26 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileSummaryView.view@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileSummaryView.view@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileSummaryView.view~dark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileSummaryView.view~dark@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileView.view@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileView.view@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileView.view~dark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/largeProfileView.view~dark@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileSummaryView.view@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileSummaryView.view@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileSummaryView.view~dark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileSummaryView.view~dark@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileView.view@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileView.view@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileView.view~dark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/ProfileExamples/profileView.view~dark@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor-intrinsic@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor-intrinsic@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor-intrinsic~dark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor-intrinsic~dark@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor-medium@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor-medium@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor-medium~dark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor-medium~dark@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor~dark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/about-editor~dark@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/avatar-and-about@2x.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/avatar-and-about@2x.gif
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/avatar-and-about~dark@2x.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/avatar-and-about~dark@2x.gif
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/horizontal-intrinsic-height.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/horizontal-intrinsic-height.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/vertical-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/vertical-large.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/vertical-medium-expandable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QEExamples/vertical-medium-expandable.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QuickEditor_Tutorial/QuickEditor_Tutorial_01_03@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QuickEditor_Tutorial/QuickEditor_Tutorial_01_03@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QuickEditor_Tutorial/QuickEditor_Tutorial_01_04@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QuickEditor_Tutorial/QuickEditor_Tutorial_01_04@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QuickEditor_Tutorial/QuickEditor_Tutorial_01_05@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QuickEditor_Tutorial/QuickEditor_Tutorial_01_05@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QuickEditor_Tutorial/QuickEditor_Tutorial_Header@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QuickEditor_Tutorial/QuickEditor_Tutorial_Header@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/QuickEditor_Tutorial/QuickEditor_Tutorial_Preview@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/QuickEditor_Tutorial/QuickEditor_Tutorial_Preview@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/gravatar-sdk@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/gravatar-sdk@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/tutorial_01_01@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/tutorial_01_01@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/tutorial_01_02@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/tutorial_01_02@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Resources/tutorial_01_header@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/GravatarUI.docc/Resources/tutorial_01_header@2x.png
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Tutorials/ContactsList/Tut_01.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import GravatarUI
3 |
4 | class TableViewController: UITableViewController {
5 | private static let cellID = "ProfileCell"
6 |
7 | lazy var dataSource = UITableViewDiffableDataSource(tableView: tableView) { [weak self] tableView, indexPath, itemIdentifier in
8 | let cell = tableView.dequeueReusableCell(withIdentifier: Self.cellID) ?? UITableViewCell(style: .default, reuseIdentifier: Self.cellID)
9 |
10 | return cell
11 | }
12 |
13 | var snapshot = NSDiffableDataSourceSnapshot()
14 | }
15 |
16 | enum Section {
17 | // Default section for the table view
18 | case main
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Tutorials/ContactsList/Tut_02.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import GravatarUI
3 |
4 | class TableViewController: UITableViewController {
5 | private static let cellID = "ProfileCell"
6 |
7 | lazy var dataSource = UITableViewDiffableDataSource(tableView: tableView) { [weak self] tableView, indexPath, itemIdentifier in
8 | let cell = tableView.dequeueReusableCell(withIdentifier: Self.cellID) ?? UITableViewCell(style: .default, reuseIdentifier: Self.cellID)
9 |
10 | return cell
11 | }
12 |
13 | var snapshot = NSDiffableDataSourceSnapshot()
14 |
15 | var models = [String: ProfileViewConfiguration]()
16 |
17 | func addProfile(with email: String) {
18 | guard !email.isEmpty else { return }
19 |
20 | // Summary profile view configuration.
21 | var config = ProfileViewConfiguration.summary()
22 | // Set in loading state
23 | config.isLoading = true
24 | // Store the configuration to get access to it later on.
25 | models[email] = config
26 | }
27 | }
28 |
29 | enum Section {
30 | case main
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Tutorials/ContactsList/Tut_05.swift:
--------------------------------------------------------------------------------
1 | class TableViewController: UITableViewController {
2 |
3 | // ... All code from before ...
4 |
5 | func fetchProfile(with email: String) async throws {
6 | // Create a profile service and fetch a profile using the given email.
7 | let service = ProfileService()
8 | let profile = try await service.fetch(with: .email(email))
9 |
10 | // Create a Summary ProfileViewConfiguration to display the profile obtained,
11 | // and store it to be retreived later on.
12 | models[email] = .summary(model: profile)
13 |
14 | // Reload the cell for the given email.
15 | // This will update the cell from the loading to the displaying info state.
16 | snapshot.reloadItems([email])
17 | await dataSource.apply(snapshot)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Tutorials/ContactsList/Tut_06.swift:
--------------------------------------------------------------------------------
1 | class TableViewController: UITableViewController {
2 |
3 | // ... All code from before ...
4 |
5 | func addProfile(with email: String) {
6 | guard !email.isEmpty else { return }
7 |
8 | var config = ProfileViewConfiguration.summary()
9 | config.isLoading = true
10 | models[email] = config
11 |
12 | snapshot.appendItems([email])
13 | dataSource.apply(snapshot)
14 |
15 | Task {
16 | do {
17 | try await fetchProfile(with: email)
18 | } catch {
19 | // Do proper error handling
20 | print(error)
21 | }
22 | }
23 | }
24 |
25 | func fetchProfile(with email: String) async throws {
26 | let service = ProfileService()
27 | let profile = try await service.fetch(with: .email(email))
28 | models[email] = .summary(model: profile)
29 |
30 | snapshot.reloadItems([email])
31 | await dataSource.apply(snapshot)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Tutorials/ContactsList/Tut_06_comparison.swift:
--------------------------------------------------------------------------------
1 | class TableViewController: UITableViewController {
2 |
3 | // ... All code from before ...
4 |
5 | func addProfile(with email: String) {
6 | guard !email.isEmpty else { return }
7 |
8 | var config = ProfileViewConfiguration.summary()
9 | config.isLoading = true
10 | models[email] = config
11 |
12 | snapshot.appendItems([email])
13 | dataSource.apply(snapshot)
14 | }
15 |
16 | func fetchProfile(with email: String) async throws {
17 | let service = ProfileService()
18 | let profile = try await service.fetch(with: .email(email))
19 | models[email] = .summary(model: profile)
20 |
21 | snapshot.reloadItems([email])
22 | await dataSource.apply(snapshot)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Tutorials/QuickEditor/QE_Tut_01.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct ContentView: View {
4 | var body: some View {
5 | VStack {
6 | Image(systemName: "globe")
7 | .imageScale(.large)
8 | .foregroundStyle(.tint)
9 | Text("Hello, world!")
10 | }
11 | .padding()
12 | }
13 | }
14 |
15 | #Preview {
16 | ContentView()
17 | }
18 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Tutorials/QuickEditor/QE_Tut_02.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct ContentView: View {
4 | @AppStorage("pickerEmail") private var email: String = ""
5 | @AppStorage("pickAuthToken") private var authToken: String = ""
6 | @State private var isPresentingPicker: Bool = false
7 |
8 | var body: some View {
9 | VStack {
10 | VStack {
11 | TextField("Enter your email", text: $email)
12 | .font(.callout)
13 | .textInputAutocapitalization(.never)
14 | .keyboardType(.emailAddress)
15 | .disableAutocorrection(true)
16 | SecureField("Enter your auth token", text: $authToken)
17 | .font(.callout)
18 | .textInputAutocapitalization(.never)
19 | .disableAutocorrection(true)
20 | }
21 | .padding(20)
22 |
23 | Button("Show Quick Editor") {
24 | isPresentingPicker = true
25 | }
26 | Spacer()
27 | }
28 | .padding()
29 | }
30 | }
31 |
32 | #Preview {
33 | ContentView()
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/GravatarUI.docc/Tutorials/Tutorials.tutorial:
--------------------------------------------------------------------------------
1 | @Tutorials(name: "Gravatar SDK Tutorials") {
2 | @Intro(title: "Learn to use Gravatar SDK") {
3 | }
4 |
5 | @Chapter(name: "Profile views as Contacts List.") {
6 | Learn how to use GravatarUI to create a contacts list.
7 |
8 | @Image(source: "tutorial_01_header.png", alt: "Add an accessible description for your image here.")
9 |
10 | @TutorialReference(tutorial: "doc:ContactsList")
11 | }
12 |
13 | @Chapter(name: "Adding the Quick Editor") {
14 | Learn how to use GravatarUI to create a contacts list.
15 |
16 | @Image(source: "QuickEditor_Tutorial_Preview.png", alt: "Add an accessible description for your image here.")
17 |
18 | @TutorialReference(tutorial: "doc:QuickEditor")
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ImageCropper/CropFrameOverlayView.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | class CropFrameOverlayView: UIView {
4 | var scrollViewFrame: CGRect = .zero {
5 | didSet {
6 | setNeedsDisplay()
7 | }
8 | }
9 |
10 | override func draw(_ rect: CGRect) {
11 | guard let context = UIGraphicsGetCurrentContext() else { return }
12 |
13 | // Fill the entire view with a semi black color
14 | context.setFillColor(UIColor.black.withAlphaComponent(0.5).cgColor)
15 | context.fill(rect)
16 |
17 | // Create a circular path for the transparent hole
18 | let circlePath = UIBezierPath(ovalIn: scrollViewFrame)
19 |
20 | // Clear the circular area
21 | context.addPath(circlePath.cgPath)
22 | context.clip(using: .evenOdd)
23 | context.clear(scrollViewFrame)
24 |
25 | // Restore context to draw the square border
26 | context.resetClip()
27 |
28 | // Draw a white border around the square
29 | context.setStrokeColor(UIColor.white.cgColor)
30 | context.setLineWidth(1)
31 | context.stroke(scrollViewFrame)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileFields/AboutMeBuilder.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @MainActor
4 | public struct AboutMeBuilder {
5 | let label: UILabel
6 | init(label: UILabel) {
7 | self.label = label
8 | }
9 |
10 | @discardableResult
11 | public func content(_ model: AboutMeModel) -> AboutMeBuilder {
12 | label.text = model.description
13 | label.font = .DS.Body.xSmall
14 | label.numberOfLines = 2
15 | return self
16 | }
17 |
18 | @discardableResult
19 | public func palette(_ paletteType: PaletteType) -> AboutMeBuilder {
20 | label.textColor = paletteType.palette.foreground.primarySlightlyDimmed
21 | return self
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileFields/DisplayNameBuilder.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @MainActor
4 | public struct DisplayNameBuilder {
5 | let label: UILabel
6 | init(label: UILabel) {
7 | self.label = label
8 | }
9 |
10 | @discardableResult
11 | public func content(_ model: DisplayNameModel) -> DisplayNameBuilder {
12 | label.text = model.displayName
13 | label.font = .DS.title2
14 | label.numberOfLines = 0
15 | return self
16 | }
17 |
18 | @discardableResult
19 | public func palette(_ paletteType: PaletteType) -> DisplayNameBuilder {
20 | label.textColor = paletteType.palette.foreground.primary
21 | return self
22 | }
23 |
24 | @discardableResult
25 | func font(_ font: UIFont) -> DisplayNameBuilder {
26 | label.font = font
27 | return self
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileFields/Model/AboutMeModel.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Gravatar
3 |
4 | public protocol AboutMeModel {
5 | var description: String { get }
6 | }
7 |
8 | extension Profile: AboutMeModel {}
9 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileFields/Model/AccountModel.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Gravatar
3 |
4 | public protocol AccountModel {
5 | var serviceLabel: String { get }
6 | var shortname: String { get }
7 | var iconURL: URL? { get }
8 | var accountURL: URL? { get }
9 | }
10 |
11 | public protocol AccountListModel {
12 | var accountsList: [AccountModel] { get }
13 | }
14 |
15 | struct GravatarAccountModel: AccountModel {
16 | let serviceLabel: String = "Gravatar"
17 | let shortname: String = "gravatar"
18 | let iconURL: URL? = nil
19 | let accountURL: URL?
20 | }
21 |
22 | extension VerifiedAccount: AccountModel {
23 | public var shortname: String {
24 | serviceLabel.lowercased()
25 | }
26 |
27 | public var iconURL: URL? {
28 | URL(string: serviceIcon)
29 | }
30 |
31 | public var accountURL: URL? {
32 | URL(string: url)
33 | }
34 | }
35 |
36 | extension Profile: AccountListModel {
37 | public var accountsList: [AccountModel] {
38 | [gravatarAccount] + verifiedAccounts
39 | }
40 |
41 | var gravatarAccount: AccountModel {
42 | GravatarAccountModel(accountURL: URL(string: profileUrl))
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileFields/Model/AvatarIdentifierProvider.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Gravatar
3 |
4 | public protocol AvatarIdentifierProvider {
5 | var avatarIdentifier: AvatarIdentifier? { get }
6 | }
7 |
8 | extension Profile: AvatarIdentifierProvider {
9 | public var avatarIdentifier: AvatarIdentifier? {
10 | .hashID(hash)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileFields/Model/DisplayNameModel.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Gravatar
3 |
4 | public protocol DisplayNameModel {
5 | var displayName: String { get }
6 | }
7 |
8 | extension Profile: DisplayNameModel {}
9 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileFields/Model/ProfileMetadataModel.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Gravatar
3 |
4 | public protocol ProfileMetadataModel {
5 | var profileURL: URL? { get }
6 | var profileEditURL: URL? { get }
7 | }
8 |
9 | extension Profile: ProfileMetadataModel {
10 | public var profileEditURL: URL? {
11 | URL(string: "https://gravatar.com/profile")
12 | }
13 |
14 | public var profileURL: URL? {
15 | URL(string: profileUrl)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileFields/Model/ProfileModel.swift:
--------------------------------------------------------------------------------
1 | public typealias ProfileModel = AboutMeModel & AccountListModel & AvatarIdentifierProvider & DisplayNameModel & PersonalInfoModel & ProfileMetadataModel
2 | public typealias ProfileSummaryModel = AvatarIdentifierProvider & DisplayNameModel & PersonalInfoModel & ProfileMetadataModel
3 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileView/ActivityIndicator/ActivityIndicator.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// Describes a general purpose activity indicator.
4 | @MainActor
5 | public protocol ActivityIndicator {
6 | associatedtype T: UIView
7 | func startAnimating(on baseView: T)
8 | func stopAnimating(on baseView: T)
9 | }
10 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileView/Placeholder/PlaceholderDisplayers/LabelPlaceholderDisplayer.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// A ``PlaceholderDisplaying`` implementation for a UILabel.
4 | @MainActor
5 | class LabelPlaceholderDisplayer: RectangularPlaceholderDisplayer {
6 | var isAnimating: Bool = false
7 |
8 | override func animationDidEnd() {
9 | isAnimating = false
10 | }
11 |
12 | override func animationWillBegin() {
13 | // If UILabel's backgroundColor is set, the animation won't be visible. So we need to clear it. This is only needed for UILabel so far.
14 | set(viewColor: .clear)
15 | isAnimating = true
16 | }
17 |
18 | override func set(viewColor newColor: UIColor?) {
19 | if !isAnimating {
20 | // If UILabel's backgroundColor is set, the animation won't be visible.
21 | // So prevent setting it if there's an animation in progress.
22 | super.set(viewColor: newColor)
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileView/Placeholder/PlaceholderDisplayers/ProfileButtonPlaceholderDisplayer.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// A ``PlaceholderDisplaying`` implementation for the "Edit/View profile" button.
4 | @MainActor
5 | class ProfileButtonPlaceholderDisplayer: RectangularPlaceholderDisplayer {
6 | override func showPlaceholder() {
7 | super.showPlaceholder()
8 | baseView.imageView?.isHidden = true
9 | baseView.titleLabel?.isHidden = true
10 | }
11 |
12 | override func hidePlaceholder() {
13 | super.hidePlaceholder()
14 | baseView.imageView?.isHidden = false
15 | baseView.titleLabel?.isHidden = false
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileView/Placeholder/UIView+Placeholder.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @MainActor
4 | extension UIView {
5 | func turnIntoPlaceholder(cornerRadius: CGFloat?, height: CGFloat?, widthRatioToParent: CGFloat?) -> [NSLayoutConstraint] {
6 | if let cornerRadius {
7 | layer.cornerRadius = cornerRadius
8 | clipsToBounds = true
9 | }
10 | var constraints: [NSLayoutConstraint] = []
11 |
12 | if let height {
13 | let heightConstraint = heightAnchor.constraint(equalToConstant: height)
14 | heightConstraint.priority = .required
15 | constraints.append(heightConstraint)
16 | }
17 |
18 | if let widthRatioToParent, let superview {
19 | let widthConstraint = widthAnchor.constraint(equalTo: superview.widthAnchor, multiplier: widthRatioToParent)
20 | widthConstraint.priority = .required
21 | constraints.append(widthConstraint)
22 | }
23 | return constraints
24 | }
25 |
26 | func resetPlaceholder(cornerRadius: CGFloat) {
27 | layer.cornerRadius = cornerRadius
28 | if cornerRadius == 0 {
29 | clipsToBounds = false
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/ProfileViewController/ProfileViewModel.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Gravatar
3 |
4 | @MainActor
5 | public class ProfileViewModel {
6 | @Published public private(set) var isLoading: Bool = false
7 | @Published public private(set) var profileFetchingResult: Result?
8 | private let profileService: ProfileService
9 |
10 | public init(profileService: ProfileService = ProfileService()) {
11 | self.profileService = profileService
12 | }
13 |
14 | public func fetchProfile(profileIdentifier: ProfileIdentifier) async {
15 | defer {
16 | isLoading = false
17 | }
18 | do {
19 | isLoading = true
20 | profileFetchingResult = try await .success(profileService.fetch(with: profileIdentifier))
21 | } catch let error as APIError {
22 | profileFetchingResult = .failure(error)
23 | } catch {
24 | profileFetchingResult = .failure(.responseError(reason: .unexpected(error)))
25 | }
26 | }
27 |
28 | public func clear() {
29 | profileFetchingResult = nil
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/calendly.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "calendly.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/calendly.imageset/calendly.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/calendly.imageset/calendly.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/fediverse.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "fediverse.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/fediverse.imageset/fediverse.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/fediverse.imageset/fediverse.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/foursquare.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "foursquare.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/foursquare.imageset/foursquare.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/foursquare.imageset/foursquare.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/github.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "github.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/github.imageset/github.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/github.imageset/github.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/gravatar.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "gravatar.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/gravatar.imageset/gravatar.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/gravatar.imageset/gravatar.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/instagram.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "instagram.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/instagram.imageset/instagram.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/instagram.imageset/instagram.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/mastodongeneric.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "mastodongeneric.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/mastodongeneric.imageset/mastodongeneric.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/mastodongeneric.imageset/mastodongeneric.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/stackoverflow.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "stackoverflow.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/stackoverflow.imageset/stackoverflow.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/stackoverflow.imageset/stackoverflow.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/tiktok.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "tiktok.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/tiktok.imageset/tiktok.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/tiktok.imageset/tiktok.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/tripit.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "tripit.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/tripit.imageset/tripit.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/tripit.imageset/tripit.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/tumblr.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "tumblr.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/tumblr.imageset/tumblr.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/tumblr.imageset/tumblr.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/twitch.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "twitch.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/twitch.imageset/twitch.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/twitch.imageset/twitch.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/twitter-alt.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "twitter-alt.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/twitter-alt.imageset/twitter-alt.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/twitter-alt.imageset/twitter-alt.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/vimeo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "vimeo.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/vimeo.imageset/vimeo.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/vimeo.imageset/vimeo.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/wordpress.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "wordpress.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/wordpress.imageset/wordpress.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/AccountIcons.xcassets/wordpress.imageset/wordpress.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/wp-link.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "LinkIcon.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/AccountIcons.xcassets/wp-link.imageset/LinkIcon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/Media.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/Media.xcassets/empty-profile-avatar.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Regular-S.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/Media.xcassets/more-horizontal.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "more-horizontal.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/Media.xcassets/more-horizontal.imageset/more-horizontal.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/Media.xcassets/pencil.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "pencil.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "template"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/Media.xcassets/pencil.imageset/pencil.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/GravatarUI/Resources/Media.xcassets/pencil.imageset/pencil.pdf
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/Media.xcassets/qe-intro-empty-profile-avatar.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Avatar 1.svg",
5 | "idiom" : "universal"
6 | },
7 | {
8 | "appearances" : [
9 | {
10 | "appearance" : "luminosity",
11 | "value" : "dark"
12 | }
13 | ],
14 | "filename" : "Avatar.svg",
15 | "idiom" : "universal"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/Resources/Media.xcassets/setup-avatar-emoji.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "emoji-smile.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/AvatarPicker/AvatarShareItem.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import UIKit
3 |
4 | struct AvatarShareItem: Identifiable {
5 | let id: String
6 | let fileURL: URL
7 | }
8 |
9 | struct PlaygroundInputItem: Identifiable {
10 | let id: String
11 | let image: Image
12 | }
13 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/AvatarPicker/Views/CTAButtonView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct CTAButtonView: View {
4 | let title: String
5 | @Environment(\.isEnabled) var isEnabled
6 |
7 | public init(_ title: String) {
8 | self.title = title
9 | }
10 |
11 | public var body: some View {
12 | Text(title)
13 | .font(.callout).fontWeight(.bold)
14 | .frame(maxWidth: .infinity)
15 | .foregroundColor(.white)
16 | .padding(.vertical, .DS.Padding.split)
17 | .padding(.horizontal, .DS.Padding.double)
18 | .background(
19 | RoundedRectangle(cornerRadius: 4)
20 | .fill(Color(uiColor: isEnabled ? .gravatarBlue : UIColor.systemFill))
21 | )
22 | }
23 | }
24 |
25 | #Preview {
26 | CTAButtonView("I am a button")
27 | .padding()
28 | CTAButtonView("I am a disabled button")
29 | .padding()
30 | .disabled(true)
31 | }
32 |
33 | #Preview("Dark mode") {
34 | CTAButtonView("I am a button")
35 | .padding()
36 | .preferredColorScheme(.dark)
37 | }
38 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/AvatarPicker/Views/DimmingActivityIndicator.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct DimmingActivityIndicator: View {
4 | public var body: some View {
5 | ZStack {
6 | Rectangle()
7 | .fill(.black.opacity(0.3))
8 | ProgressView().tint(.white)
9 | }
10 | }
11 | }
12 |
13 | #Preview {
14 | DimmingActivityIndicator()
15 | .frame(width: 80, height: 80)
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/AvatarPicker/Views/DimmingButton.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | /// Dims the parent and puts a retry button on it.
4 | struct DimmingButton: View {
5 | let imageName: String
6 | let action: () -> Void
7 |
8 | var body: some View {
9 | Button(
10 | action: action,
11 | label: {
12 | ZStack {
13 | Rectangle()
14 | .fill(.black.opacity(0.3))
15 | Image(systemName: imageName)
16 | .resizable()
17 | .aspectRatio(contentMode: .fill)
18 | .frame(width: 20, height: 20)
19 | }
20 | }
21 | )
22 | .foregroundColor(Color.white)
23 | }
24 | }
25 |
26 | /// Dims the parent and puts an exclamation mark on it.
27 | struct DimmingErrorButton: View {
28 | let action: () -> Void
29 |
30 | var body: some View {
31 | DimmingButton(imageName: "exclamationmark.triangle.fill", action: action)
32 | }
33 | }
34 |
35 | #Preview {
36 | VStack {
37 | DimmingErrorButton {}.frame(width: 100, height: 100)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/AvatarPicker/Views/EmailText.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct EmailText: View {
4 | enum Constants {
5 | static let bottomSpacing: CGFloat = .DS.Padding.double
6 | }
7 |
8 | let email: Email?
9 | var body: some View {
10 | if let email = email?.rawValue, !email.isEmpty {
11 | Text(email)
12 | .padding(.bottom, Constants.bottomSpacing / 2)
13 | .font(.footnote)
14 | .foregroundColor(Color(UIColor.secondaryLabel))
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/AvatarPicker/Views/ShareSheet.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | /// Use `ShareLink` after iOS 16+.
4 | struct ShareSheet: UIViewControllerRepresentable {
5 | var items: [Any]
6 | var activities: [UIActivity]? = nil
7 |
8 | func makeUIViewController(context: Context) -> UIActivityViewController {
9 | let controller = UIActivityViewController(activityItems: items, applicationActivities: activities)
10 | controller.excludedActivityTypes = [.print,
11 | .postToWeibo,
12 | .postToTencentWeibo,
13 | .addToReadingList,
14 | .postToVimeo,
15 | .openInIBooks]
16 | return controller
17 | }
18 |
19 | func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {
20 | // No need to update dynamically
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/ImageCropper.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct ImageCropper: UIViewControllerRepresentable, ImageEditorView {
4 | let inputImage: UIImage
5 | var editingDidFinish: @Sendable (UIImage) -> Void
6 | var onCancel: () -> Void
7 |
8 | typealias UIViewControllerType = UINavigationController
9 |
10 | init(inputImage: UIImage, editingDidFinish: @escaping @Sendable (UIImage) -> Void, onCancel: @escaping () -> Void) {
11 | self.inputImage = inputImage
12 | self.editingDidFinish = editingDidFinish
13 | self.onCancel = onCancel
14 | }
15 |
16 | func makeUIViewController(context: UIViewControllerRepresentableContext) -> UINavigationController {
17 | ImageCropperViewController.wrappedInNavigationViewController(
18 | image: inputImage,
19 | onCompletion: editingDidFinish,
20 | onCancel: onCancel
21 | )
22 | }
23 |
24 | func updateUIViewController(
25 | _ uiViewController: UINavigationController,
26 | context: UIViewControllerRepresentableContext
27 | ) {}
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/LoadingIndicatorView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct LoadingIndicatorView: View {
4 | var body: some View {
5 | VStack(spacing: 0) {
6 | ProgressView()
7 | .progressViewStyle(CircularProgressViewStyle())
8 | .controlSize(.regular)
9 | }
10 | .padding(.top, .DS.Padding.large)
11 | }
12 | }
13 |
14 | #Preview {
15 | LoadingIndicatorView()
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/ModalPresentationModifier.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct ModalItemPresentationModifier: ViewModifier where T: Identifiable {
4 | @Binding var item: T?
5 |
6 | let onDismiss: (() -> Void)?
7 | let modalViewBuilder: (T) -> ModalView
8 |
9 | init(item: Binding, onDismiss: (() -> Void)? = nil, @ViewBuilder modalView: @escaping (T) -> ModalView) {
10 | self._item = item
11 | self.onDismiss = onDismiss
12 | self.modalViewBuilder = modalView
13 | }
14 |
15 | func body(content: Content) -> some View {
16 | content
17 | .sheet(item: $item) { item in
18 | modalViewBuilder(item)
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/OAuthSession/KeychainToken.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct KeychainToken: Codable {
4 | let token: String
5 | var isExpired: Bool = false
6 |
7 | init?(data: Data) {
8 | let decoder = JSONDecoder()
9 | do {
10 | let decodedToken = try decoder.decode(KeychainToken.self, from: data)
11 | self = decodedToken
12 | } catch {
13 | return nil
14 | }
15 | }
16 |
17 | init(token: String) {
18 | self.token = token
19 | }
20 |
21 | var data: Data? {
22 | let encoder = JSONEncoder()
23 | return try? encoder.encode(self)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/OAuthSession/OldAuthenticationSession+Environment.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | private struct OAuthSessionKey: EnvironmentKey {
4 | static let defaultValue: OAuthSession = .shared
5 | }
6 |
7 | extension EnvironmentValues {
8 | public var oauthSession: OAuthSession {
9 | get { self[OAuthSessionKey.self] }
10 | set { self[OAuthSessionKey.self] = newValue }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/ProfileEditor/QuickEditorUpdate.swift:
--------------------------------------------------------------------------------
1 | /// A marker protocol representing a type of update that has occurred.
2 | ///
3 | /// Concrete implementations are defined under the `QuickEditorUpdate` namespace.
4 | ///
5 | /// Example usage:
6 | ///
7 | /// As an example:
8 | /// ```swift
9 | /// updateHandler: { updateType in
10 | /// switch updateType {
11 | /// case is QuickEditorUpdate.Avatar:
12 | /// // Handle avatar update
13 | /// case let update as QuickEditorUpdate.AboutInfo:
14 | /// // Handle profile update using `update.profile`
15 | /// default:
16 | /// break
17 | /// }
18 | /// }
19 | /// ```
20 | public protocol QuickEditorUpdateType {}
21 |
22 | /// A namespace for concrete update types conforming to `QuickEditorUpdateType`.
23 | public enum QuickEditorUpdate {
24 | /// Represents an update to the user's avatar.
25 | public struct Avatar: QuickEditorUpdateType {}
26 |
27 | /// Represents an update to the user's profile information.
28 | public struct AboutInfo: QuickEditorUpdateType {
29 | /// The updated Profile model.
30 | public let profile: Profile
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Sources/GravatarUI/SwiftUI/SafariView.swift:
--------------------------------------------------------------------------------
1 | import SafariServices
2 | import SwiftUI
3 |
4 | struct SafariView: UIViewControllerRepresentable {
5 | let url: URL
6 |
7 | func makeUIViewController(context: UIViewControllerRepresentableContext) -> SFSafariViewController {
8 | SFSafariViewController(url: url)
9 | }
10 |
11 | func updateUIViewController(_ uiViewController: SFSafariViewController, context: UIViewControllerRepresentableContext) {
12 | // No updates needed for SafariViewController
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Sources/TestHelpers/HTTPURLResponse+Extension.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Gravatar
3 |
4 | extension HTTPURLResponse {
5 | package static func successResponse(with url: URL = URL(string: "https://gravatar.com")!) -> HTTPURLResponse {
6 | HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
7 | }
8 |
9 | package static func errorResponse(with url: URL = URL(string: "https://gravatar.com")!, code: Int) -> HTTPURLResponse {
10 | HTTPURLResponse(url: url, statusCode: code, httpVersion: nil, headerFields: nil)!
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Sources/TestHelpers/ImageDownloadService+Extension.swift:
--------------------------------------------------------------------------------
1 | import Gravatar
2 |
3 | extension ImageDownloadService {
4 | package static func mock(with session: URLSessionProtocol, cache: ImageCaching? = nil) -> ImageDownloadService {
5 | let service = ImageDownloadService(urlSession: session, cache: cache)
6 | return service
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Sources/TestHelpers/Resources/avatarSelected.json:
--------------------------------------------------------------------------------
1 | {
2 | "image_id": "9862792c565394...",
3 | "image_url": "https://2.gravatar.com/userimage/1/991a7b71cf9f34...?size=512",
4 | "rating": "G",
5 | "updated_date": "2024-09-18T10:17:53Z",
6 | "alt_text": "John Appleseed's avatar",
7 | "selected": true
8 | }
9 |
--------------------------------------------------------------------------------
/Sources/TestHelpers/Resources/avatarSetAltTextResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "image_id": "991a7b71cf9f34...",
3 | "image_url": "https://2.gravatar.com/userimage/1/991a7b71cf934ea2...?size=512",
4 | "rating": "PG",
5 | "updated_date": "2024-09-18T10:17:53Z",
6 | "alt_text": "Updated Alt Text"
7 | }
8 |
--------------------------------------------------------------------------------
/Sources/TestHelpers/Resources/avatarSetRatingResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "image_id": "991a7b71cf9f34...",
3 | "image_url": "https://2.gravatar.com/userimage/1/991a7b71cf934ea2...?size=512",
4 | "rating": "PG",
5 | "updated_date": "2024-09-18T10:17:53Z",
6 | "alt_text": "John Appleseed's avatar"
7 | }
8 |
--------------------------------------------------------------------------------
/Sources/TestHelpers/Resources/avatarUploadResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "image_id": "6f3eac1c67f970f2a0c2ea8",
3 | "image_url": "https://2.gravatar.com/userimage/133992/9862792c5653946c?size=512",
4 | "rating": "G",
5 | "updated_date": "2024-09-19T11:46:04Z",
6 | "alt_text": "John Appleseed's avatar"
7 | }
8 |
--------------------------------------------------------------------------------
/Sources/TestHelpers/Resources/example_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/TestHelpers/Resources/example_avatar.png
--------------------------------------------------------------------------------
/Sources/TestHelpers/Resources/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/TestHelpers/Resources/placeholder.png
--------------------------------------------------------------------------------
/Sources/TestHelpers/Resources/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Sources/TestHelpers/Resources/test.png
--------------------------------------------------------------------------------
/Sources/TestHelpers/TestImageProcessor.swift:
--------------------------------------------------------------------------------
1 | import Gravatar
2 | import UIKit
3 |
4 | package final class TestImageProcessor: ImageProcessor {
5 | let image: UIImage?
6 | package init(image: UIImage? = nil) {
7 | self.image = image
8 | }
9 |
10 | package func process(_: Data) -> UIImage? {
11 | image
12 | }
13 | }
14 |
15 | package final class FailingImageProcessor: ImageProcessor {
16 | package func process(_: Data) -> UIImage? {
17 | nil
18 | }
19 |
20 | package init() {}
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/TestHelpers/TestURLSessionError.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | package class TestURLSessionError: NSError, @unchecked Sendable {
4 | let message: String
5 |
6 | package init(message: String) {
7 | self.message = message
8 | super.init(domain: NSURLErrorDomain, code: 1)
9 | }
10 |
11 | @available(*, unavailable)
12 | required init?(coder: NSCoder) {
13 | fatalError("init(coder:) has not been implemented")
14 | }
15 |
16 | override package var localizedDescription: String {
17 | message
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Tests/GravatarTests/EmailTests.swift:
--------------------------------------------------------------------------------
1 | import Gravatar
2 | import XCTest
3 |
4 | final class EmailTests: XCTestCase {
5 | private let testEmail = "test@example.com"
6 |
7 | func testEmailSanitized() {
8 | let sanitaryEmailString = "test@example.com"
9 | let unsanitaryEmailString = " TeST@Example.com "
10 |
11 | let hopefullySantizedEmail: Email = .init(unsanitaryEmailString)
12 |
13 | XCTAssertEqual(hopefullySantizedEmail.rawValue, sanitaryEmailString)
14 | }
15 |
16 | func testEmailIDIsHashID() {
17 | let emailHashID: HashID = .init(email: .init(testEmail))
18 |
19 | let email: Email = .init(testEmail)
20 |
21 | XCTAssertEqual(email.id, emailHashID.id)
22 | }
23 |
24 | func testEmailRawValueIsEmailString() throws {
25 | let sut: Email = try XCTUnwrap(.init(rawValue: testEmail))
26 |
27 | XCTAssertEqual(sut.rawValue, testEmail)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Tests/GravatarTests/GravatarImageCacheTests.swift:
--------------------------------------------------------------------------------
1 | import Gravatar
2 | import TestHelpers
3 | import XCTest
4 |
5 | final class GravatarImageCacheTests: XCTestCase {
6 | private let key = "ImageKey"
7 |
8 | func testSetAndGet() {
9 | let cache = ImageCache()
10 | cache.setEntry(.ready(ImageHelper.testImage), for: key)
11 | let image = cache.getEntry(with: key)
12 | XCTAssertNotNil(image)
13 | }
14 |
15 | func testRequestingMultipleTimes() {
16 | let cache = ImageCache()
17 | let task = Task {
18 | ImageHelper.testImage
19 | }
20 | cache.setEntry(.inProgress(task), for: key)
21 | let image = cache.getEntry(with: key)
22 | XCTAssertNotNil(image)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Tests/GravatarTests/HashIDTests.swift:
--------------------------------------------------------------------------------
1 | import Gravatar
2 | import XCTest
3 |
4 | final class HashIDTests: XCTestCase {
5 | func testInitWithHashString() {
6 | let hash = "testhash123"
7 |
8 | let sut: HashID = .init(hash)
9 |
10 | XCTAssertEqual(sut.id, hash)
11 | }
12 |
13 | func testInitWithEmail() {
14 | let testEmail = "test@example.com"
15 | let email: Email = .init(testEmail)
16 |
17 | let sut: HashID = .init(email: email)
18 |
19 | XCTAssertEqual(sut.id, email.id)
20 | }
21 |
22 | func testUnSanitizedEmailProducesNoramlizedHashID() {
23 | let sanitizedEmail: Email = .init("test@example.com")
24 | let unSanitizedEmail: Email = .init(" TeST@ExAmPle.com ")
25 |
26 | let hashSanitizedEmail: HashID = .init(email: sanitizedEmail)
27 | let hashUnSanitizedEmail: HashID = .init(email: unSanitizedEmail)
28 |
29 | XCTAssertEqual(hashSanitizedEmail, hashUnSanitizedEmail)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Tests/GravatarTests/RenameMeTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | final class RenameMeTests_swift: XCTestCase {
4 | override func setUpWithError() throws {
5 | // Put setup code here. This method is called before the invocation of each test method in the class.
6 | }
7 |
8 | override func tearDownWithError() throws {
9 | // Put teardown code here. This method is called after the invocation of each test method in the class.
10 | }
11 |
12 | func testExample() throws {
13 | // This is an example of a functional test case.
14 | // Use XCTAssert and related functions to verify your tests produce the correct results.
15 | // Any test you write for XCTest can be annotated as throws and async.
16 | // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
17 | // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
18 | }
19 |
20 | func testPerformanceExample() throws {
21 | // This is an example of a performance test case.
22 | self.measure {
23 | // Put the code you want to measure the time of here.
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Tests/GravatarTests/Resources/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarTests/Resources/placeholder.png
--------------------------------------------------------------------------------
/Tests/GravatarTests/Resources/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarTests/Resources/test.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/Bundle+ResourceBundle.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | #if !SWIFT_PACKAGE
4 | private class BundleFinder: NSObject {}
5 | #endif
6 |
7 | extension Bundle {
8 | /// Returns the GravatarUITests Bundle
9 | /// If installed via CocoaPods, this will be GravatarUITestsResources.bundle,
10 | /// otherwise it will be the module bundle.
11 | ///
12 | class var testsBundle: Bundle {
13 | #if SWIFT_PACKAGE
14 | return Bundle.module
15 | #else
16 | let defaultBundle = Bundle(for: BundleFinder.self)
17 | // If installed with CocoaPods, resources will be in GravatarUITestsResources.bundle
18 | if let bundleURL = defaultBundle.resourceURL,
19 | let resourceBundle = Bundle(url: bundleURL.appendingPathComponent("GravatarUITestsResources.bundle"))
20 | {
21 | return resourceBundle
22 | }
23 | // Otherwise, the default bundle is used for resources
24 | return defaultBundle
25 | #endif
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Tests/GravatarUITests/KeychainTokenTests.swift:
--------------------------------------------------------------------------------
1 | @testable import GravatarUI
2 | import Testing
3 |
4 | struct KeychainTokenTests {
5 | @Test
6 | func testKeychainTokenCreatedFromData() async throws {
7 | let token = KeychainToken(token: "someToken")
8 | let data = token.data
9 | #expect(data != nil)
10 |
11 | let decodedToken = KeychainToken(data: data!)
12 | #expect(decodedToken?.token == token.token)
13 | #expect(decodedToken?.isExpired == token.isExpired)
14 | }
15 |
16 | @Test
17 | func testExpiredKeychainTokenCreatedFromData() async throws {
18 | var token = KeychainToken(token: "someToken")
19 | token.isExpired = true
20 |
21 | let data = token.data
22 | #expect(data != nil)
23 |
24 | let decodedToken = KeychainToken(data: data!)
25 | #expect(decodedToken?.token == token.token)
26 | #expect(decodedToken?.isExpired == true)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Tests/GravatarUITests/Resources/example_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/Resources/example_avatar.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/Resources/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/Resources/placeholder.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/Resources/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/Resources/test.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/Snapshotting+Additions.swift:
--------------------------------------------------------------------------------
1 | import SnapshotTesting
2 | import SwiftUI
3 | import XCTest
4 |
5 | extension Snapshotting where Value: SwiftUI.View, Format == UIImage {
6 | static func testStrategy(userInterfaceStyle: UIUserInterfaceStyle = .light, layout: SwiftUISnapshotLayout = .sizeThatFits) -> Self {
7 | let deviceConfig: ViewImageConfig = .iPhone13
8 | let traits = UITraitCollection(traitsFrom: [
9 | UITraitCollection(displayScale: deviceConfig.traits.displayScale),
10 | UITraitCollection(userInterfaceStyle: userInterfaceStyle),
11 | ])
12 |
13 | return .image(
14 | layout: layout,
15 | traits: traits
16 | )
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Tests/GravatarUITests/TestActivityIndicator.swift:
--------------------------------------------------------------------------------
1 | import GravatarUI
2 | import UIKit
3 |
4 | class TestActivityIndicator: ActivityIndicatorProvider {
5 | var animating = false
6 | private(set) var startCount: Int = 0
7 | private(set) var stopCount: Int = 0
8 |
9 | func startAnimatingView() {
10 | animating = true
11 | startCount += 1
12 | }
13 |
14 | func stopAnimatingView() {
15 | animating = false
16 | stopCount += 1
17 | }
18 |
19 | lazy var view: UIView = {
20 | let newView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
21 | newView.backgroundColor = .blue
22 | return newView
23 | }()
24 |
25 | func sizeStrategy(in view: UIView) -> ActivityIndicatorSizeStrategy {
26 | .intrinsicSize
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewAllFieldsFixedHeight.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewAllFieldsFixedHeight.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewAllFieldsFixedHeight.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewAllFieldsFixedHeight.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewAllFieldsIntrinsicHeight.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewAllFieldsIntrinsicHeight.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewAllFieldsIntrinsicHeight.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewAllFieldsIntrinsicHeight.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewExtraFieldsIntrinsicHeight.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewExtraFieldsIntrinsicHeight.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewExtraFieldsIntrinsicHeight.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewExtraFieldsIntrinsicHeight.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewOneFieldFixedHeight.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewOneFieldFixedHeight.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewOneFieldFixedHeight.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewOneFieldFixedHeight.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewPersonalFieldsIntrinsicHeight.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewPersonalFieldsIntrinsicHeight.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewPersonalFieldsIntrinsicHeight.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewPersonalFieldsIntrinsicHeight.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewProfessionalFieldsIntrinsicHeight.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewProfessionalFieldsIntrinsicHeight.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewProfessionalFieldsIntrinsicHeight.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorViewProfessionalFieldsIntrinsicHeight.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorWithUnsavedChanges.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorWithUnsavedChanges.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorWithUnsavedChanges.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAboutEditorWithUnsavedChanges.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAuthErrorStateAfterSave.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAuthErrorStateAfterSave.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAuthErrorStateAfterSave.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testAuthErrorStateAfterSave.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testLoadingErrorState.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testLoadingErrorState.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testLoadingErrorState.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testLoadingErrorState.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testLoadingState.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testLoadingState.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testLoadingState.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutEditorViewTests/testLoadingState.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutMeBuilderTests/testAboutMe.testAboutMe-Dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutMeBuilderTests/testAboutMe.testAboutMe-Dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutMeBuilderTests/testAboutMe.testAboutMe-Light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutMeBuilderTests/testAboutMe.testAboutMe-Light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AboutMeBuilderTests/testAboutMeWithSmallWidth.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AboutMeBuilderTests/testAboutMeWithSmallWidth.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileView.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileView.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileView.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileView.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileViewEmpty.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileViewEmpty.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileViewEmpty.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileViewEmpty.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileViewWithoutLocation.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileViewWithoutLocation.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileViewWithoutLocation.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/AvatarPickerProfileViewTests/testAvatarPickerProfileViewWithoutLocation.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/CropFrameOverlayViewTests/testCropFrameOverlay.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/CropFrameOverlayViewTests/testCropFrameOverlay.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameField.testDisplayNameField-Dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameField.testDisplayNameField-Dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameField.testDisplayNameField-Light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameField.testDisplayNameField-Light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameFieldWithMissingDisplayName.testDisplayNameFieldWithMissingDisplayName-Dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameFieldWithMissingDisplayName.testDisplayNameFieldWithMissingDisplayName-Dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameFieldWithMissingDisplayName.testDisplayNameFieldWithMissingDisplayName-Light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameFieldWithMissingDisplayName.testDisplayNameFieldWithMissingDisplayName-Light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameFieldWithMissingNames.testDisplayNameFieldWithMissingNames-Dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameFieldWithMissingNames.testDisplayNameFieldWithMissingNames-Dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameFieldWithMissingNames.testDisplayNameFieldWithMissingNames-Light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameFieldWithMissingNames.testDisplayNameFieldWithMissingNames-Light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameFieldWithSmallWidth.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/DisplayNameBuilderTests/testDisplayNameFieldWithSmallWidth.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testInitiallyEmptyLargeProfileSummaryView.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testInitiallyEmptyLargeProfileSummaryView.dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testInitiallyEmptyLargeProfileSummaryView.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testInitiallyEmptyLargeProfileSummaryView.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryCustomAvatarViewImageViewSubview.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryCustomAvatarViewImageViewSubview.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryView.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryView.dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryView.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryView.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewCustomAvatarImageViewSubviewCustomStyle.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewCustomAvatarImageViewSubviewCustomStyle.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewCustomAvatarImageViewWrapper.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewCustomAvatarImageViewWrapper.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewCustomAvatarView.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewCustomAvatarView.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewEmptyState.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewEmptyState.dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewEmptyState.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewEmptyState.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewEmptyStateCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewEmptyStateCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewLoadingStateClears.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewLoadingStateClears.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewLoadingStateClearsWhenDataIsPresent.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewLoadingStateClearsWhenDataIsPresent.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewLoadingStateClearsWhenEmpty.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewLoadingStateClearsWhenEmpty.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewPlaceholderCanUpdateColors.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewPlaceholderCanUpdateColors.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewPlaceholdersCanHide.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewPlaceholdersCanHide.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewPlaceholdersCanHideCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewPlaceholdersCanHideCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewPlaceholdersCanShow.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewPlaceholdersCanShow.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewPlaceholdersCanShowCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileSummaryViewTests/testLargeProfileSummaryViewPlaceholdersCanShowCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testInitiallyEmptyLargeProfileView.Dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testInitiallyEmptyLargeProfileView.Dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testInitiallyEmptyLargeProfileView.Light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testInitiallyEmptyLargeProfileView.Light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileCustomAvatarImageViewWrapper.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileCustomAvatarImageViewWrapper.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileCustomAvatarView.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileCustomAvatarView.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileCustomAvatarViewImageViewSubview.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileCustomAvatarViewImageViewSubview.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileView.testLargeProfileView-Dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileView.testLargeProfileView-Dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileView.testLargeProfileView-Light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileView.testLargeProfileView-Light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewCustomAvatarImageViewSubviewCustomStyle.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewCustomAvatarImageViewSubviewCustomStyle.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewEmptyState.testLargeProfileView-Dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewEmptyState.testLargeProfileView-Dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewEmptyState.testLargeProfileView-Light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewEmptyState.testLargeProfileView-Light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewEmptyStateCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewEmptyStateCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewLoadingStateClearsWhenDataIsPresent.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewLoadingStateClearsWhenDataIsPresent.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewLoadingStateClearsWhenEmpty.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewLoadingStateClearsWhenEmpty.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewPlaceholderCanUpdateColors.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewPlaceholderCanUpdateColors.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewPlaceholdersCanHide.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewPlaceholdersCanHide.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewPlaceholdersCanHideCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewPlaceholdersCanHideCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewPlaceholdersCanShow.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewPlaceholdersCanShow.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewPlaceholdersCanShowCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/LargeProfileViewTests/testLargeProfileViewPlaceholdersCanShowCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/PersonalInfoBuilderTests/testPersonalInfoCustom.testPersonalInfoFull-Dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/PersonalInfoBuilderTests/testPersonalInfoCustom.testPersonalInfoFull-Dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/PersonalInfoBuilderTests/testPersonalInfoCustom.testPersonalInfoFull-Light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/PersonalInfoBuilderTests/testPersonalInfoCustom.testPersonalInfoFull-Light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/PersonalInfoBuilderTests/testPersonalInfoFull.testPersonalInfoFull-Dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/PersonalInfoBuilderTests/testPersonalInfoFull.testPersonalInfoFull-Dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/PersonalInfoBuilderTests/testPersonalInfoFull.testPersonalInfoFull-Light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/PersonalInfoBuilderTests/testPersonalInfoFull.testPersonalInfoFull-Light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/PersonalInfoBuilderTests/testPersonalInfoWithSmallWidth.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/PersonalInfoBuilderTests/testPersonalInfoWithSmallWidth.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileButtonTests/testProfileButtonSnapshots.edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileButtonTests/testProfileButtonSnapshots.edit.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileButtonTests/testProfileButtonSnapshots.view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileButtonTests/testProfileButtonSnapshots.view.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileConfigurationTests/testCustomAvatarStyle.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileConfigurationTests/testCustomAvatarStyle.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testInitiallyEmptyProfileSummaryView.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testInitiallyEmptyProfileSummaryView.dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testInitiallyEmptyProfileSummaryView.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testInitiallyEmptyProfileSummaryView.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryView.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryView.dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryView.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryView.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewCustomAvatarImageViewSubviewCustomStyle.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewCustomAvatarImageViewSubviewCustomStyle.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewCustomAvatarImageViewWrapper.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewCustomAvatarImageViewWrapper.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewCustomAvatarView.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewCustomAvatarView.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewCustomAvatarViewImageViewSubview.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewCustomAvatarViewImageViewSubview.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewEmptyState.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewEmptyState.dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewEmptyState.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewEmptyState.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewEmptyStateCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewEmptyStateCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewPlaceholdersCanHide.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewPlaceholdersCanHide.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewPlaceholdersCanHideCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewPlaceholdersCanHideCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewPlaceholdersCanShow.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewPlaceholdersCanShow.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewPlaceholdersCanShowCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileSummaryViewPlaceholdersCanShowCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileViewSummaryLoadingStateClearsWhenDataIsPresent.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileViewSummaryLoadingStateClearsWhenDataIsPresent.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileViewSummaryLoadingStateClearsWhenEmpty.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileViewSummaryLoadingStateClearsWhenEmpty.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileViewSummaryPlaceholderCanUpdateColors.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileSummaryViewTests/testProfileViewSummaryPlaceholderCanUpdateColors.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testInitiallyEmptyProfileView.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testInitiallyEmptyProfileView.dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testInitiallyEmptyProfileView.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testInitiallyEmptyProfileView.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileView.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileView.dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileView.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileView.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewCustomAvatarImageViewSubviewCustomStyle.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewCustomAvatarImageViewSubviewCustomStyle.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewCustomAvatarImageViewWrapper.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewCustomAvatarImageViewWrapper.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewCustomAvatarView.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewCustomAvatarView.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewCustomAvatarViewImageViewSubview.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewCustomAvatarViewImageViewSubview.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewEmptyState.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewEmptyState.dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewEmptyState.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewEmptyState.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewEmptyStateCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewEmptyStateCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewLoadingStateClearsWhenDataIsPresent.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewLoadingStateClearsWhenDataIsPresent.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewLoadingStateClearsWhenEmpty.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewLoadingStateClearsWhenEmpty.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewPlaceholderCanUpdateColors.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewPlaceholderCanUpdateColors.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewPlaceholdersCanHide.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewPlaceholdersCanHide.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewPlaceholdersCanHideCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewPlaceholdersCanHideCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewPlaceholdersCanShow.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewPlaceholdersCanShow.light.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewPlaceholdersCanShowCustomPalette.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProfileViewTests/testProfileViewPlaceholdersCanShowCustomPalette.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileSummaryView.view-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileSummaryView.view-dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileSummaryView.view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileSummaryView.view.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileView.view-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileView.view-dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileView.view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/largeProfileView.view.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileSummaryView.view-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileSummaryView.view-dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileSummaryView.view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileSummaryView.view.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileView.view-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileView.view-dark.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileView.view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/ProvileViewSnapshots/profileView.view.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeView.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeView.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeView.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeView.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeViewWithError.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeViewWithError.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeViewWithError.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeViewWithError.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeViewWithoutToken.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeViewWithoutToken.1.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeViewWithoutToken.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/QuickEditorNoticeViewTests/testQuickEditorNoticeViewWithoutToken.2.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testAccountButtonsPlaceholderDisplayer.placeholder-shown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testAccountButtonsPlaceholderDisplayer.placeholder-shown.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testBackgroundColorPlaceholderDisplayer.placeholder-hidden.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testBackgroundColorPlaceholderDisplayer.placeholder-hidden.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testBackgroundColorPlaceholderDisplayer.placeholder-shown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testBackgroundColorPlaceholderDisplayer.placeholder-shown.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testProfileButtonPlaceholderDisplayer.placeholder-hidden.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testProfileButtonPlaceholderDisplayer.placeholder-hidden.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testProfileButtonPlaceholderDisplayer.placeholder-shown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testProfileButtonPlaceholderDisplayer.placeholder-shown.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testRectangularColorPlaceholderDisplayer.placeholder-hidden.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testRectangularColorPlaceholderDisplayer.placeholder-hidden.png
--------------------------------------------------------------------------------
/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testRectangularColorPlaceholderDisplayer.placeholder-shown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/Gravatar-SDK-iOS/71350ef7274a989ca2ed89c512f8b9dd99bc8c3d/Tests/GravatarUITests/__Snapshots__/TestPlaceholderDisplayers/testRectangularColorPlaceholderDisplayer.placeholder-shown.png
--------------------------------------------------------------------------------
/fastlane/example.env:
--------------------------------------------------------------------------------
1 | # You don't need to fill in these values for Fastlane to run.
2 | #
3 | # However, if a lane requires some of these environment values and they are not set here, it will fail.
4 | MATCH_S3_ACCESS_KEY=
5 | MATCH_S3_SECRET_ACCESS_KEY=
6 |
--------------------------------------------------------------------------------
/openapi/GravatarOpenAPIClient/.openapi-generator/FILES:
--------------------------------------------------------------------------------
1 | Sources/GravatarOpenAPIClient/Models/AssociatedResponse.swift
2 | Sources/GravatarOpenAPIClient/Models/Avatar.swift
3 | Sources/GravatarOpenAPIClient/Models/AvatarRating.swift
4 | Sources/GravatarOpenAPIClient/Models/CryptoWalletAddress.swift
5 | Sources/GravatarOpenAPIClient/Models/GalleryImage.swift
6 | Sources/GravatarOpenAPIClient/Models/Interest.swift
7 | Sources/GravatarOpenAPIClient/Models/Language.swift
8 | Sources/GravatarOpenAPIClient/Models/Link.swift
9 | Sources/GravatarOpenAPIClient/Models/ModelError.swift
10 | Sources/GravatarOpenAPIClient/Models/Profile.swift
11 | Sources/GravatarOpenAPIClient/Models/ProfileContactInfo.swift
12 | Sources/GravatarOpenAPIClient/Models/ProfilePayments.swift
13 | Sources/GravatarOpenAPIClient/Models/SetEmailAvatarRequest.swift
14 | Sources/GravatarOpenAPIClient/Models/UpdateAvatarRequest.swift
15 | Sources/GravatarOpenAPIClient/Models/UpdateProfileRequest.swift
16 | Sources/GravatarOpenAPIClient/Models/VerifiedAccount.swift
17 |
--------------------------------------------------------------------------------
/openapi/GravatarOpenAPIClient/.openapi-generator/VERSION:
--------------------------------------------------------------------------------
1 | 7.5.0
2 |
--------------------------------------------------------------------------------
/openapi/templates/model.mustache:
--------------------------------------------------------------------------------
1 | {{#models}}{{#model}}//
2 | // {{classname}}.swift
3 | //
4 | // Generated by openapi-generator
5 | // https://openapi-generator.tech
6 | //
7 |
8 | import Foundation
9 | {{#useVapor}}
10 | import Vapor{{/useVapor}}
11 | {{#swiftUseApiNamespace}}
12 |
13 | @available(*, deprecated, renamed: "{{projectName}}API.{{classname}}")
14 | {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} typealias {{classname}} = {{projectName}}API.{{classname}}
15 |
16 | extension {{projectName}}API {
17 | {{/swiftUseApiNamespace}}
18 | {{#description}}/// {{{.}}}
19 | ///{{/description}}{{#isDeprecated}}
20 | @available(*, deprecated, message: "This schema is deprecated."){{/isDeprecated}}{{#vendorExtensions.x-is-one-of-interface}}
21 | {{> modelOneOf}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{#isArray}}
22 | {{> modelArray}}{{/isArray}}{{^isArray}}{{#isEnum}}
23 | {{> modelEnum}}{{/isEnum}}{{^isEnum}}
24 | {{> modelObject}}{{/isEnum}}{{/isArray}}{{/vendorExtensions.x-is-one-of-interface}}{{/model}}{{/models}}
25 | {{#swiftUseApiNamespace}}
26 | }
27 | {{/swiftUseApiNamespace}}
28 |
--------------------------------------------------------------------------------
/openapi/templates/modelInlineEnumDeclaration.mustache:
--------------------------------------------------------------------------------
1 | {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum {{enumName}}: {{^isContainer}}{{dataType}}{{/isContainer}}{{#isContainer}}String{{/isContainer}}, {{#useVapor}}Content, Hashable{{/useVapor}}{{^useVapor}}Codable{{^isContainer}}{{^isString}}{{^isInteger}}{{^isFloat}}{{^isDouble}}, JSONEncodable{{/isDouble}}{{/isFloat}}{{/isInteger}}{{/isString}}{{/isContainer}}{{/useVapor}}, CaseIterable{{#enumUnknownDefaultCase}}{{#isInteger}}, CaseIterableDefaultsLast{{/isInteger}}{{#isFloat}}, CaseIterableDefaultsLast{{/isFloat}}{{#isDouble}}, CaseIterableDefaultsLast{{/isDouble}}{{#isString}}, CaseIterableDefaultsLast{{/isString}}{{#isContainer}}, CaseIterableDefaultsLast{{/isContainer}}{{/enumUnknownDefaultCase}}, Sendable {
2 | {{#allowableValues}}
3 | {{#enumVars}}
4 | case {{{name}}} = {{{value}}}
5 | {{/enumVars}}
6 | {{/allowableValues}}
7 | }
8 |
--------------------------------------------------------------------------------
/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Gravatar
4 | VERSION = '3.4.0-rc.1'
5 | SWIFT_VERSIONS = [
6 | '5.10'
7 | ].freeze
8 | end
9 |
--------------------------------------------------------------------------------