Update HeroImage to match the BigIcon component from Compound. (#3439)

We can move it across in a following PR.
This commit is contained in:
Doug 2024-10-23 12:13:14 +01:00 committed by GitHub
parent 01886bb4d8
commit 6584b4d084
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
259 changed files with 552 additions and 545 deletions

View File

@ -962,7 +962,6 @@
D43F0503EF2CBC55272538FE /* SDKGeneratedMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F079B5DBD0D85FEA687AAE /* SDKGeneratedMocks.swift */; };
D46C33F8B61B55F0C8C2D15F /* LocationRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B2AC540DE619B36832A5DB5 /* LocationRoomTimelineItem.swift */; };
D4CB979EB4FE26AAD9F9A72B /* UserProfileScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 604A69C081B935D6A38DE6D8 /* UserProfileScreenModels.swift */; };
D4D5595C4A2A702CFF4E94FF /* HeroImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EC2F1622C5BBABED6012E12 /* HeroImage.swift */; };
D4D7CCECC6C0AAFC42E165BB /* NotificationPermissionsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9BBB18FB27F09032AD8769 /* NotificationPermissionsScreenViewModel.swift */; };
D53B80EF02C1062E68659EDD /* ReportContentViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 086C19086DD16E9B38E25954 /* ReportContentViewModelTests.swift */; };
D55AF9B5B55FEED04771A461 /* RoomFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A008E57D52B07B78DFAD1BB /* RoomFlowCoordinator.swift */; };
@ -1132,6 +1131,7 @@
FB595EC9C00AB32F39034055 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A37E2FACFD041CE466223CD /* SceneDelegate.swift */; };
FBD402E3170EB1ED0D1AA672 /* EncryptionKeyProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2355398E4A55DA5A89128AD1 /* EncryptionKeyProvider.swift */; };
FBF09B6C900415800DDF2A21 /* EmojiProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C113E0CB7E15E9765B1817A /* EmojiProvider.swift */; };
FC0EEFF630F34899953BB950 /* BigIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01FD1171FF40E34D707FD00 /* BigIcon.swift */; };
FC10228E73323BDC09526F97 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = 4278261E147DB2DE5CFB7FC5 /* PostHog */; };
FC8B95EC506E6BB5793D81CE /* ClientProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E34685D186453E429ADEE58E /* ClientProtocolTests.swift */; };
FCD3F2B82CAB29A07887A127 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 2B43F2AF7456567FE37270A7 /* KeychainAccess */; };
@ -1751,7 +1751,6 @@
7E492690C8B27A892C194CC4 /* AdvancedSettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenCoordinator.swift; sourceTree = "<group>"; };
7E8562F4D7DE073BC32902AB /* EncryptionResetScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionResetScreenViewModelProtocol.swift; sourceTree = "<group>"; };
7EB58E4E8D6D634C246AD5C2 /* RoomInviterLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomInviterLabel.swift; sourceTree = "<group>"; };
7EC2F1622C5BBABED6012E12 /* HeroImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeroImage.swift; sourceTree = "<group>"; };
7EECE8B331CD169790EF284F /* BugReportScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugReportScreenViewModelTests.swift; sourceTree = "<group>"; };
7F615A00DB223FF3280204D2 /* UserDiscoveryServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoveryServiceProtocol.swift; sourceTree = "<group>"; };
7FB2253D36E81E045E1CB432 /* Duration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Duration.swift; sourceTree = "<group>"; };
@ -2114,6 +2113,7 @@
CDE3F3911FF7CC639BDE5844 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
CEE20623EB4A9B88FB29F2BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/SAS.strings; sourceTree = "<group>"; };
CEE41494C837AA403A06A5D9 /* UnitTests.xctestplan */ = {isa = PBXFileReference; path = UnitTests.xctestplan; sourceTree = "<group>"; };
D01FD1171FF40E34D707FD00 /* BigIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BigIcon.swift; sourceTree = "<group>"; };
D071F86CD47582B9196C9D16 /* UserDiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDiscoverySection.swift; sourceTree = "<group>"; };
D086854995173E897F993C26 /* AdvancedSettingsScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreenViewModelProtocol.swift; sourceTree = "<group>"; };
D09A267106B9585D3D0CFC0D /* ClientError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientError.swift; sourceTree = "<group>"; };
@ -2955,8 +2955,8 @@
CC743C7A85E3171BCBF0A653 /* AvatarHeaderView.swift */,
9A028783CFFF861C5E44FFB1 /* BadgeLabel.swift */,
C1FA515B3B0D61EF1E907D2D /* BadgeView.swift */,
D01FD1171FF40E34D707FD00 /* BigIcon.swift */,
8CC23C63849452BC86EA2852 /* ButtonStyle.swift */,
7EC2F1622C5BBABED6012E12 /* HeroImage.swift */,
B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */,
C352359663A0E52BA20761EE /* LoadableImage.swift */,
FFECCE59967018204876D0A5 /* LocationMarkerView.swift */,
@ -6343,6 +6343,7 @@
D876EC0FED3B6D46C806912A /* AvatarSize.swift in Sources */,
7A25D6926A2C01DB8D0D67A5 /* BadgeLabel.swift in Sources */,
A4B0BAD62A12ED76BD611B79 /* BadgeView.swift in Sources */,
FC0EEFF630F34899953BB950 /* BigIcon.swift in Sources */,
38546A6010A2CF240EC9AF73 /* BindableState.swift in Sources */,
EB9F4688006B52E69DF5358F /* BlankFormCoordinator.swift in Sources */,
369BF960E52BBEE61F8A5BD1 /* BlockedUsersScreen.swift in Sources */,
@ -6494,7 +6495,6 @@
D34E328E9E65904358248FDD /* GlobalSearchScreenModels.swift in Sources */,
55D18AA4F4A2257642EBDB94 /* GlobalSearchScreenViewModel.swift in Sources */,
E32A18802EB37EEE3EF7B965 /* GlobalSearchScreenViewModelProtocol.swift in Sources */,
D4D5595C4A2A702CFF4E94FF /* HeroImage.swift in Sources */,
0C1E537A49ABB386F7554D4A /* HighlightedTimelineItemModifier.swift in Sources */,
964B9D2EC38C488C360CE0C9 /* HomeScreen.swift in Sources */,
62C5876C4254C58C2086F0DE /* HomeScreenContent.swift in Sources */,

View File

@ -10,39 +10,36 @@ import SwiftUI
/// An image that is styled for use as the main/top/hero screen icon. This component
/// takes a compound icon. If you would like to apply it to an SFSymbol, you can call
/// the `heroImage()` modifier directly on the Image.
struct HeroImage: View {
/// the `bigIcon()` modifier directly on the Image.
struct BigIcon: View {
enum Style {
case normal
case subtle
case defaultSolid
case `default`
case alertSolid
case alert
case successSolid
case success
case critical
case criticalOnSecondary
var foregroundColor: Color {
switch self {
case .normal:
.compound.iconPrimary
case .subtle:
case .defaultSolid, .default:
.compound.iconSecondary
case .success:
.compound.iconSuccessPrimary
case .critical, .criticalOnSecondary:
case .alertSolid, .alert:
.compound.iconCriticalPrimary
case .successSolid, .success:
.compound.iconSuccessPrimary
}
}
var backgroundFillColor: Color {
switch self {
case .normal:
case .defaultSolid:
.compound.bgSubtleSecondary
case .subtle:
.compound.bgSubtlePrimary
case .success:
.compound.bgSuccessSubtle
case .critical:
case .alertSolid:
.compound.bgCriticalSubtle
case .criticalOnSecondary:
case .successSolid:
.compound.bgSuccessSubtle
case .default, .alert, .success:
.compound.bgCanvasDefault
}
}
@ -50,32 +47,32 @@ struct HeroImage: View {
/// The icon that is shown.
let icon: KeyPath<CompoundIcons, Image>
var style: Style = .normal
var style: Style = .defaultSolid
var body: some View {
CompoundIcon(icon, size: .custom(42), relativeTo: .title)
.modifier(HeroImageModifier(style: style))
CompoundIcon(icon, size: .custom(32), relativeTo: .title)
.modifier(BigIconModifier(style: style))
}
}
extension Image {
/// Styles the image for use as the main/top/hero screen icon. You should prefer
/// the HeroImage component when possible, by using an icon from Compound.
func heroImage(insets: CGFloat = 16, style: HeroImage.Style = .normal) -> some View {
/// the BigIcon component when possible, by using an icon from Compound.
func bigIcon(insets: CGFloat = 16, style: BigIcon.Style = .defaultSolid) -> some View {
resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.scaledPadding(insets, relativeTo: .title)
.modifier(HeroImageModifier(style: style))
.modifier(BigIconModifier(style: style))
}
}
private struct HeroImageModifier: ViewModifier {
let style: HeroImage.Style
private struct BigIconModifier: ViewModifier {
let style: BigIcon.Style
func body(content: Content) -> some View {
content
.scaledFrame(size: 70, relativeTo: .title)
.scaledFrame(size: 64, relativeTo: .title)
.foregroundColor(style.foregroundColor)
.background {
RoundedRectangle(cornerRadius: 14)
@ -87,22 +84,32 @@ private struct HeroImageModifier: ViewModifier {
// MARK: - Previews
struct HeroImage_Previews: PreviewProvider, TestablePreview {
struct BigIcon_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
VStack(spacing: 20) {
VStack(spacing: 40) {
HStack(spacing: 20) {
HeroImage(icon: \.lockSolid)
BigIcon(icon: \.lockSolid)
Image(systemName: "hourglass")
.heroImage()
.bigIcon()
Image(asset: Asset.Images.serverSelectionIcon)
.heroImage(insets: 19)
.bigIcon(insets: 19)
}
HStack(spacing: 20) {
HeroImage(icon: \.helpSolid, style: .subtle)
HeroImage(icon: \.checkCircleSolid, style: .success)
HeroImage(icon: \.error, style: .critical)
HeroImage(icon: \.error, style: .criticalOnSecondary)
VStack(spacing: 20) {
HStack(spacing: 20) {
BigIcon(icon: \.helpSolid)
BigIcon(icon: \.helpSolid, style: .default)
}
HStack(spacing: 20) {
BigIcon(icon: \.error, style: .alertSolid)
BigIcon(icon: \.error, style: .alert)
}
HStack(spacing: 20) {
BigIcon(icon: \.checkCircleSolid, style: .successSolid)
BigIcon(icon: \.checkCircleSolid, style: .success)
}
}
}
}

View File

@ -58,7 +58,7 @@ struct AppLockSetupPINScreen: View {
var header: some View {
VStack(spacing: 8) {
HeroImage(icon: \.lockSolid)
BigIcon(icon: \.lockSolid)
.padding(.bottom, 8)
Text(context.viewState.title)

View File

@ -45,7 +45,7 @@ struct LoginScreen: View {
/// The header containing the title and icon.
var header: some View {
VStack(spacing: 8) {
HeroImage(icon: \.lockSolid)
BigIcon(icon: \.lockSolid)
.padding(.bottom, 8)
Text(L10n.screenLoginTitleWithHomeserver(context.viewState.homeserver.address))

View File

@ -29,7 +29,7 @@ struct ServerConfirmationScreen: View {
var header: some View {
VStack(spacing: 8) {
Image(systemSymbol: .personCropCircleFill)
.heroImage()
.bigIcon()
.padding(.bottom, 8)
Text(context.viewState.title)

View File

@ -32,7 +32,7 @@ struct ServerSelectionScreen: View {
var header: some View {
VStack(spacing: 8) {
Image(asset: Asset.Images.serverSelectionIcon)
.heroImage(insets: 19)
.bigIcon(insets: 19)
.padding(.bottom, 8)
Text(L10n.screenChangeServerTitle)

View File

@ -15,7 +15,7 @@ struct EncryptionResetPasswordScreen: View {
var body: some View {
FullscreenDialog {
VStack(spacing: 16) {
HeroImage(icon: \.lockSolid)
BigIcon(icon: \.lockSolid)
Text(L10n.screenResetEncryptionPasswordTitle)
.foregroundColor(.compound.textPrimary)

View File

@ -39,7 +39,7 @@ struct EncryptionResetScreen: View {
private var header: some View {
VStack(spacing: 8) {
HeroImage(icon: \.error, style: .criticalOnSecondary)
BigIcon(icon: \.error, style: .alert)
.padding(.bottom, 8)
Text(L10n.screenEncryptionResetTitle)

View File

@ -88,7 +88,7 @@ struct JoinRoomScreen: View {
@ViewBuilder
private var knockedView: some View {
VStack(spacing: 16) {
HeroImage(icon: \.checkCircleSolid, style: .success)
BigIcon(icon: \.checkCircleSolid, style: .successSolid)
VStack(spacing: 8) {
Text(L10n.screenJoinRoomKnockSentTitle)
.font(.compound.headingMDBold)

View File

@ -35,7 +35,7 @@ struct AnalyticsPromptScreen: View {
private var header: some View {
VStack(spacing: 8) {
HeroImage(icon: \.chart)
BigIcon(icon: \.chart)
.padding(.bottom, 8)
Text(L10n.screenAnalyticsPromptTitle(InfoPlistReader.main.bundleDisplayName))

View File

@ -37,7 +37,7 @@ struct IdentityConfirmationScreen: View {
@ViewBuilder
private var screenHeader: some View {
VStack(spacing: 0) {
HeroImage(icon: \.lockSolid)
BigIcon(icon: \.lockSolid)
.padding(.bottom, 16)
Text(L10n.screenIdentityConfirmationTitle)

View File

@ -29,7 +29,7 @@ struct IdentityConfirmedScreen: View {
@ViewBuilder
private var screenHeader: some View {
VStack(spacing: 0) {
HeroImage(icon: \.checkCircle, style: .success)
BigIcon(icon: \.checkCircle, style: .successSolid)
.padding(.bottom, 16)
Text(L10n.screenIdentityConfirmedTitle)

View File

@ -27,7 +27,7 @@ struct NotificationPermissionsScreen: View {
/// The main content of the screen that is shown inside the scroll view.
private var mainContent: some View {
VStack(spacing: 8) {
HeroImage(icon: \.notificationsSolid)
BigIcon(icon: \.notificationsSolid)
.padding(.bottom, 8)
Text(L10n.screenNotificationOptinTitle)

View File

@ -58,11 +58,11 @@ struct SessionVerificationScreen: View {
private var screenHeader: some View {
VStack(spacing: 0) {
if context.viewState.verificationState == .initial {
HeroImage(icon: \.lockSolid)
BigIcon(icon: \.lockSolid)
.padding(.bottom, 16)
} else {
Image(systemName: headerImageName)
.heroImage()
.bigIcon()
.padding(.bottom, 16)
}

View File

@ -50,7 +50,7 @@ struct PinnedEventsTimelineScreen: View {
private var content: some View {
if timelineContext.viewState.pinnedEventIDs.isEmpty {
VStack(spacing: 16) {
HeroImage(icon: \.pin, style: .normal)
BigIcon(icon: \.pin)
Text(L10n.screenPinnedTimelineEmptyStateHeadline)
.font(.compound.headingSMSemibold)
.foregroundStyle(.compound.textPrimary)

View File

@ -41,7 +41,7 @@ struct QRCodeLoginScreen: View {
FullscreenDialog {
VStack(alignment: .leading, spacing: 40) {
VStack(spacing: 16) {
HeroImage(icon: \.computer, style: .subtle)
BigIcon(icon: \.computer, style: .default)
VStack(spacing: 8) {
Text(L10n.screenQrCodeLoginInitialStateTitle(InfoPlistReader.main.productionAppName))
@ -101,7 +101,7 @@ struct QRCodeLoginScreen: View {
VStack(spacing: 16) {
switch state {
case .deviceCode:
HeroImage(icon: \.computer, style: .subtle)
BigIcon(icon: \.computer, style: .default)
VStack(spacing: 8) {
Text(L10n.screenQrCodeLoginDeviceCodeTitle)
@ -115,7 +115,7 @@ struct QRCodeLoginScreen: View {
.multilineTextAlignment(.center)
}
case .verificationCode:
HeroImage(icon: \.lock, style: .subtle)
BigIcon(icon: \.lock, style: .default)
VStack(spacing: 8) {
Text(L10n.screenQrCodeLoginVerifyCodeTitle)
@ -136,7 +136,7 @@ struct QRCodeLoginScreen: View {
FullscreenDialog {
VStack(spacing: 40) {
VStack(spacing: 16) {
HeroImage(icon: \.takePhotoSolid, style: .subtle)
BigIcon(icon: \.takePhotoSolid, style: .default)
Text(L10n.screenQrCodeLoginScanningStateTitle)
.foregroundColor(.compound.textPrimary)
@ -256,7 +256,7 @@ struct QRCodeLoginScreen: View {
switch errorState {
case .noCameraPermission:
VStack(spacing: 16) {
HeroImage(icon: \.takePhotoSolid, style: .subtle)
BigIcon(icon: \.takePhotoSolid, style: .default)
VStack(spacing: 8) {
Text(L10n.screenQrCodeLoginNoCameraPermissionStateTitle)
@ -273,7 +273,7 @@ struct QRCodeLoginScreen: View {
case .connectionNotSecure:
VStack(spacing: 40) {
VStack(spacing: 16) {
HeroImage(icon: \.error, style: .criticalOnSecondary)
BigIcon(icon: \.error, style: .alert)
VStack(spacing: 8) {
Text(L10n.screenQrCodeLoginConnectionNoteSecureStateTitle)
@ -339,7 +339,7 @@ struct QRCodeLoginScreen: View {
}
VStack(spacing: 16) {
HeroImage(icon: \.error, style: .criticalOnSecondary)
BigIcon(icon: \.error, style: .alert)
VStack(spacing: 8) {
Text(title)

View File

@ -38,7 +38,7 @@ struct ResolveVerifiedUserSendFailureScreen: View {
var header: some View {
VStack(spacing: 8) {
HeroImage(icon: \.error, style: .critical)
BigIcon(icon: \.error, style: .alertSolid)
.padding(.bottom, 8)
Text(context.viewState.title)

View File

@ -40,7 +40,7 @@ struct SecureBackupKeyBackupScreen: View {
private var disableBackupSection: some View {
VStack(spacing: 16) {
HeroImage(icon: \.keyOffSolid)
BigIcon(icon: \.keyOffSolid)
Text(L10n.screenKeyBackupDisableTitle)
.foregroundColor(.compound.textPrimary)

View File

@ -15,7 +15,7 @@ struct SecureBackupLogoutConfirmationScreen: View {
var body: some View {
FullscreenDialog {
VStack(spacing: 16) {
HeroImage(icon: \.keyOffSolid)
BigIcon(icon: \.keyOffSolid)
content
}
.padding()

View File

@ -53,7 +53,7 @@ struct SecureBackupRecoveryKeyScreen: View {
private var header: some View {
VStack(spacing: 16) {
HeroImage(icon: \.keySolid)
BigIcon(icon: \.keySolid)
Text(context.viewState.title)
.foregroundColor(.compound.textPrimary)

View File

@ -83,6 +83,12 @@ extension PreviewTests {
}
}
func test_bigIcon() {
for preview in BigIcon_Previews._allPreviews {
assertSnapshots(matching: preview)
}
}
func test_blockedUsersScreen() {
for preview in BlockedUsersScreen_Previews._allPreviews {
assertSnapshots(matching: preview)
@ -221,12 +227,6 @@ extension PreviewTests {
}
}
func test_heroImage() {
for preview in HeroImage_Previews._allPreviews {
assertSnapshots(matching: preview)
}
}
func test_highlightedTimelineItemModifier() {
for preview in HighlightedTimelineItemModifier_Previews._allPreviews {
assertSnapshots(matching: preview)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More