diff --git a/WooCommerce/Classes/View Modifiers/View+DividerStyle.swift b/WooCommerce/Classes/View Modifiers/View+DividerStyle.swift new file mode 100644 index 00000000000..9b228a8868e --- /dev/null +++ b/WooCommerce/Classes/View Modifiers/View+DividerStyle.swift @@ -0,0 +1,24 @@ +import SwiftUI + +/// Custom view modifier for applying the default divider style. +struct DividerStyle: ViewModifier { + + func body(content: Content) -> some View { + content + .foregroundColor(Color(.separator)) + .frame(height: Layout.height) + } +} + +private extension DividerStyle { + enum Layout { + static let height: CGFloat = 1 + } +} + +extension View { + /// Applies the default divider style to a view. + func dividerStyle() -> some View { + self.modifier(DividerStyle()) + } +} diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Domains/DomainSettingsListView.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Domains/DomainSettingsListView.swift new file mode 100644 index 00000000000..cea0ddddbb0 --- /dev/null +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Domains/DomainSettingsListView.swift @@ -0,0 +1,75 @@ +import SwiftUI + +/// Shows a list of domains in domain settings with a CTA to add a domain. +struct DomainSettingsListView: View { + let domains: [DomainSettingsViewModel.Domain] + let addDomain: () -> Void + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + Text(Localization.header.uppercased()) + .padding(Layout.headerPadding) + .foregroundColor(Color(.secondaryLabel)) + .captionStyle() + + ForEach(domains, id: \.name) { domain in + VStack(alignment: .leading) { + Text(domain.name) + if let renewalDate = domain.autoRenewalDate { + Text(String(format: Localization.renewalDateFormat, renewalDate.toString(dateStyle: .medium, timeStyle: .none))) + .foregroundColor(Color(.secondaryLabel)) + } + } + .padding(Layout.domainPadding) + Divider() + .dividerStyle() + .padding(Layout.dividerPadding) + } + + Button(Localization.addDomain) { + addDomain() + } + .padding(Layout.actionButtonPadding) + .buttonStyle(PlusButtonStyle()) + + Divider() + .dividerStyle() + .padding(Layout.dividerPadding) + } + } +} + +private extension DomainSettingsListView { + enum Localization { + static let header = NSLocalizedString( + "Your site domains", + comment: "Header text of the site's domain list in domain settings." + ) + static let renewalDateFormat = NSLocalizedString( + "Renews on %1$@", + comment: "Renewal date of a site's domain in domain settings. " + + "Reads like `Renews on October 11, 2023`." + ) + static let addDomain = NSLocalizedString( + "Add a domain", + comment: "Title of button to add a domain in domain settings." + ) + } + + enum Layout { + static let headerPadding: EdgeInsets = .init(top: 18, leading: 16, bottom: 6, trailing: 16) + static let domainPadding: EdgeInsets = .init(top: 10, leading: 16, bottom: 10, trailing: 16) + static let actionButtonPadding: EdgeInsets = .init(top: 18, leading: 16, bottom: 18, trailing: 23) + static let dividerPadding: EdgeInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 0) + } +} + +struct DomainSettingsListView_Previews: PreviewProvider { + static var previews: some View { + DomainSettingsListView(domains: [ + .init(isPrimary: true, name: "play.store", autoRenewalDate: .distantFuture), + .init(isPrimary: false, name: "app.store", autoRenewalDate: nil), + .init(isPrimary: false, name: "woo.store", autoRenewalDate: .now) + ], addDomain: {}) + } +} diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Domains/DomainSettingsView.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Domains/DomainSettingsView.swift index a5f8197041e..43233a2db25 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Domains/DomainSettingsView.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Domains/DomainSettingsView.swift @@ -33,6 +33,7 @@ struct DomainSettingsView: View { FreeStagingDomainView(domain: freeDomain) Spacer() } + .padding(.horizontal, insets: Layout.defaultHorizontalPadding) } if viewModel.hasDomainCredit { @@ -40,7 +41,9 @@ struct DomainSettingsView: View { } if viewModel.domains.isNotEmpty { - // TODO: 8558 - show domain list with search domain action + DomainSettingsListView(domains: viewModel.domains) { + // TODO: 8558 - search domain action + } } } .padding(Layout.contentPadding) @@ -82,7 +85,8 @@ private extension DomainSettingsView { enum Layout { static let dividerHeight: CGFloat = 1 static let bottomContentPadding: EdgeInsets = .init(top: 10, leading: 16, bottom: 10, trailing: 16) - static let contentPadding: EdgeInsets = .init(top: 39, leading: 16, bottom: 16, trailing: 16) + static let contentPadding: EdgeInsets = .init(top: 39, leading: 0, bottom: 16, trailing: 0) + static let defaultHorizontalPadding: EdgeInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16) static let contentSpacing: CGFloat = 36 } } diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index 01a98935e4f..aef3d8cfaab 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -197,6 +197,7 @@ 02521E11243DC3C400DC7810 /* CancellableMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02521E10243DC3C400DC7810 /* CancellableMedia.swift */; }; 02524A5D252ED5C60033E7BD /* ProductVariationLoadUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02524A5C252ED5C60033E7BD /* ProductVariationLoadUseCaseTests.swift */; }; 02535CBB25823F7A00E137BB /* ShippingLabelPaperSize+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02535CBA25823F7A00E137BB /* ShippingLabelPaperSize+UI.swift */; }; + 02562AD0296D1FD100980404 /* View+DividerStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02562ACF296D1FD100980404 /* View+DividerStyle.swift */; }; 02564A88246C047C00D6DB2A /* Optional+StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02564A87246C047C00D6DB2A /* Optional+StringTests.swift */; }; 02564A8A246CDF6100D6DB2A /* ProductsTopBannerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02564A89246CDF6100D6DB2A /* ProductsTopBannerFactory.swift */; }; 02564A8C246CE38E00D6DB2A /* SwappableSubviewContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02564A8B246CE38E00D6DB2A /* SwappableSubviewContainerView.swift */; }; @@ -370,6 +371,7 @@ 02B2829027C352DA004A332A /* RefreshableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B2828F27C352DA004A332A /* RefreshableScrollView.swift */; }; 02B2829227C4808D004A332A /* InfiniteScrollIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B2829127C4808D004A332A /* InfiniteScrollIndicator.swift */; }; 02B2C831249C4C8D0040C83C /* TextFieldTextAlignmentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B2C830249C4C8D0040C83C /* TextFieldTextAlignmentTests.swift */; }; + 02B41A96296D09D100FE3311 /* DomainSettingsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B41A95296D09D100FE3311 /* DomainSettingsListView.swift */; }; 02B653AC2429F7BF00A9C839 /* MockTaxClassStoresManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B653AB2429F7BF00A9C839 /* MockTaxClassStoresManager.swift */; }; 02B8650F24A9E2D800265779 /* Product+SwiftUIPreviewHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02B8650E24A9E2D800265779 /* Product+SwiftUIPreviewHelpers.swift */; }; 02BA12852461674B008D8325 /* Optional+String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BA12842461674B008D8325 /* Optional+String.swift */; }; @@ -2265,6 +2267,7 @@ 02521E10243DC3C400DC7810 /* CancellableMedia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancellableMedia.swift; sourceTree = ""; }; 02524A5C252ED5C60033E7BD /* ProductVariationLoadUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductVariationLoadUseCaseTests.swift; sourceTree = ""; }; 02535CBA25823F7A00E137BB /* ShippingLabelPaperSize+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ShippingLabelPaperSize+UI.swift"; sourceTree = ""; }; + 02562ACF296D1FD100980404 /* View+DividerStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+DividerStyle.swift"; sourceTree = ""; }; 02564A87246C047C00D6DB2A /* Optional+StringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+StringTests.swift"; sourceTree = ""; }; 02564A89246CDF6100D6DB2A /* ProductsTopBannerFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductsTopBannerFactory.swift; sourceTree = ""; }; 02564A8B246CE38E00D6DB2A /* SwappableSubviewContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwappableSubviewContainerView.swift; sourceTree = ""; }; @@ -2438,6 +2441,7 @@ 02B2828F27C352DA004A332A /* RefreshableScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshableScrollView.swift; sourceTree = ""; }; 02B2829127C4808D004A332A /* InfiniteScrollIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteScrollIndicator.swift; sourceTree = ""; }; 02B2C830249C4C8D0040C83C /* TextFieldTextAlignmentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldTextAlignmentTests.swift; sourceTree = ""; }; + 02B41A95296D09D100FE3311 /* DomainSettingsListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainSettingsListView.swift; sourceTree = ""; }; 02B653AB2429F7BF00A9C839 /* MockTaxClassStoresManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTaxClassStoresManager.swift; sourceTree = ""; }; 02B8650E24A9E2D800265779 /* Product+SwiftUIPreviewHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Product+SwiftUIPreviewHelpers.swift"; sourceTree = ""; }; 02BA12842461674B008D8325 /* Optional+String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+String.swift"; sourceTree = ""; }; @@ -4546,6 +4550,7 @@ 02C37B7A2967096800F0CF9E /* DomainSettingsView.swift */, 02C37B7C2967B72A00F0CF9E /* FreeStagingDomainView.swift */, 02DE39D82968647100BB31D4 /* DomainSettingsViewModel.swift */, + 02B41A95296D09D100FE3311 /* DomainSettingsListView.swift */, ); path = Domains; sourceTree = ""; @@ -5497,6 +5502,7 @@ AE77EA4F27A47C99006A21BD /* View+AddingDividers.swift */, AED089F127C794BC0020AE10 /* View+CurrencySymbol.swift */, CC666F2327F329DC0045AF1E /* View+DiscardChanges.swift */, + 02562ACF296D1FD100980404 /* View+DividerStyle.swift */, ); path = "View Modifiers"; sourceTree = ""; @@ -10913,6 +10919,7 @@ 025FDD3423717D4900824006 /* AztecEditorViewController.swift in Sources */, 451B1740258B7EFB00836277 /* AddAttributeOptionsViewController.swift in Sources */, AE6C4FDF28A15BFE00EAC00D /* FeatureAnnouncementCardCell.swift in Sources */, + 02562AD0296D1FD100980404 /* View+DividerStyle.swift in Sources */, CE5F462723AAC8C0006B1A5C /* RefundDetailsViewModel.swift in Sources */, D8815B132638686200EDAD62 /* CardPresentModalError.swift in Sources */, 02EAA4CA2911004B00918DAB /* TextFieldStyles.swift in Sources */, @@ -10942,6 +10949,7 @@ 0269A63C2581D26C007B49ED /* ShippingLabelPrintingStepListView.swift in Sources */, 3188533C2639FE5800F66A9C /* CardReaderSettingsPresentedViewViewModel.swift in Sources */, DE792E1B26EF37ED0071200C /* DefaultConnectivityObserver.swift in Sources */, + 02B41A96296D09D100FE3311 /* DomainSettingsListView.swift in Sources */, 029F29FE24DA5B2D004751CA /* ProductInventorySettingsViewModel.swift in Sources */, 57CFCD28248845B4003F51EC /* PrimarySectionHeaderView.swift in Sources */, 023A059A24135F2600E3FC99 /* ReviewsViewController.swift in Sources */,