Use block versions of Section header/footer

This commit is contained in:
Davide De Rosa 2022-05-01 19:43:33 +02:00
parent d8b19b952a
commit 48d499569b
24 changed files with 173 additions and 167 deletions

View File

@ -69,22 +69,20 @@ struct AboutView: View {
}
private var githubSubview: some View {
Section(
header: Text(Unlocalized.About.github)
) {
Section {
Button(Unlocalized.About.readme) {
URL.openURL(readmeURL)
}
Button(Unlocalized.About.changelog) {
URL.openURL(changelogURL)
}
} header: {
Text(Unlocalized.About.github)
}
}
private var webSubview: some View {
Section(
header: Text(L10n.About.Sections.Web.header)
) {
Section {
Button(L10n.About.Items.Website.caption) {
URL.openURL(readmeURL)
}
@ -97,6 +95,8 @@ struct AboutView: View {
Button(L10n.About.Items.PrivacyPolicy.caption) {
URL.openURL(privacyURL)
}
} header: {
Text(L10n.About.Sections.Web.header)
}
}
}

View File

@ -63,11 +63,7 @@ struct AccountView: View {
var body: some View {
List {
Section(
footer: metadata?.localizedGuidanceString.map {
Text($0)
}
) {
Section {
TextField(usernamePlaceholder ?? L10n.Account.Items.Username.placeholder, text: $liveAccount.username)
.textContentType(.username)
.disableAutocorrection(true)
@ -85,6 +81,10 @@ struct AccountView: View {
.disableAutocorrection(true)
.autocapitalization(.none)
.withLeadingText(L10n.Account.Items.Password.caption)
} footer: {
metadata?.localizedGuidanceString.map {
Text($0)
}
}
if vpnProtocol == .openVPN {
metadata?.openVPNGuidanceURL.map { guidanceURL in

View File

@ -109,26 +109,27 @@ extension AddHostView {
}
private var encryptionSection: some View {
Section(
header: Text(L10n.Global.Strings.encryption)
) {
Section {
SecureField(L10n.AddProfile.Host.Sections.Encryption.footer, text: $viewModel.encryptionPassphrase) {
processProfile(replacingExisting: false)
}
} header: {
Text(L10n.Global.Strings.encryption)
}
}
private var completeSection: some View {
Section(
header: Text(L10n.AddProfile.Shared.title),
footer: themeErrorMessage(viewModel.errorMessage)
) {
Section {
Text(Unlocalized.Network.url)
.withTrailingText(url.lastPathComponent)
viewModel.processedProfile.vpnProtocols.first.map {
Text(L10n.Global.Strings.protocol)
.withTrailingText($0.description)
}
} header: {
Text(L10n.AddProfile.Shared.title)
} footer: {
themeErrorMessage(viewModel.errorMessage)
}
}

View File

@ -39,12 +39,13 @@ enum AddProfileView {
let onCommit: () -> Void
var body: some View {
Section(
header: Text(L10n.Global.Strings.name),
footer: themeErrorMessage(errorMessage)
) {
Section {
TextField(L10n.Global.Placeholders.profileName, text: $profileName, onCommit: onCommit)
.themeValidProfileName()
} header: {
Text(L10n.Global.Strings.name)
} footer: {
themeErrorMessage(errorMessage)
}
}
}
@ -55,10 +56,10 @@ enum AddProfileView {
@Binding var profileName: String
var body: some View {
Section(
header: Text(L10n.AddProfile.Shared.Views.Existing.header)
) {
Section {
ForEach(headers, content: existingProfileButton)
} header: {
Text(L10n.AddProfile.Shared.Views.Existing.header)
}
}

View File

@ -84,9 +84,7 @@ struct AddProviderView: View {
}
private var mainSection: some View {
Section(
footer: Text(L10n.AddProfile.Provider.Sections.Vpn.footer)
) {
Section {
let protos = availableVPNProtocols
if !protos.isEmpty {
themeTextPicker(
@ -97,14 +95,16 @@ struct AddProviderView: View {
)
}
updateListButton
} footer: {
Text(L10n.AddProfile.Provider.Sections.Vpn.footer)
}
}
private var providersSection: some View {
Section(
footer: themeErrorMessage(viewModel.errorMessage)
) {
Section {
ForEach(providers, content: providerRow)
} footer: {
themeErrorMessage(viewModel.errorMessage)
}.disabled(viewModel.isFetchingAnyProvider)
}

View File

@ -110,9 +110,7 @@ extension DiagnosticsView {
}
private var debugLogSection: some View {
Section(
footer: Text(L10n.Diagnostics.Sections.DebugLog.footer)
) {
Section {
let url = debugLogURL
NavigationLink(L10n.DebugLog.title) {
url.map {
@ -123,6 +121,8 @@ extension DiagnosticsView {
}
}.disabled(url == nil)
Toggle(L10n.Diagnostics.Items.MasksPrivateData.caption, isOn: $appManager.masksPrivateData)
} footer: {
Text(L10n.Diagnostics.Sections.DebugLog.footer)
}
}

View File

@ -95,16 +95,17 @@ struct DonateView: View {
}
private var productsSection: some View {
Section(
header: Text(L10n.Donate.Sections.OneTime.header),
footer: Text(L10n.Donate.Sections.OneTime.footer)
.xxxThemeTruncation()
) {
Section {
if !productManager.isRefreshingProducts {
ForEach(productManager.donations, id: \.productIdentifier, content: productRow)
} else {
ProgressView()
}
} header: {
Text(L10n.Donate.Sections.OneTime.header)
} footer: {
Text(L10n.Donate.Sections.OneTime.footer)
.xxxThemeTruncation()
}
}

View File

@ -63,9 +63,7 @@ extension EndpointAdvancedView {
extension EndpointAdvancedView.OpenVPNView {
private var ipv4Section: some View {
builder.ipv4.map { cfg in
Section(
header: Text(Unlocalized.Network.ipv4)
) {
Section {
themeLongContentLinkDefault(
L10n.Global.Strings.address,
content: .constant(builder.ipv4.localizedAddress)
@ -81,15 +79,15 @@ extension EndpointAdvancedView.OpenVPNView {
content: .constant(route.localizedDescription)
)
}
} header: {
Text(Unlocalized.Network.ipv4)
}
}
}
private var ipv6Section: some View {
builder.ipv6.map { cfg in
Section(
header: Text(Unlocalized.Network.ipv6)
) {
Section {
themeLongContentLinkDefault(
L10n.Global.Strings.address,
content: .constant(builder.ipv6.localizedAddress)
@ -105,15 +103,15 @@ extension EndpointAdvancedView.OpenVPNView {
content: .constant(route.localizedDescription)
)
}
} header: {
Text(Unlocalized.Network.ipv6)
}
}
}
private func communicationSection(configuration: OpenVPN.Configuration) -> some View {
configuration.communicationSettings.map { settings in
Section(
header: Text(L10n.Endpoint.Advanced.Openvpn.Sections.Communication.header)
) {
Section {
settings.cipher.map {
Text(L10n.Endpoint.Advanced.Openvpn.Items.Cipher.caption)
.withTrailingText($0.localizedDescription)
@ -126,14 +124,14 @@ extension EndpointAdvancedView.OpenVPNView {
Text(Unlocalized.VPN.xor)
.withTrailingText($0.localizedDescriptionAsXOR)
}
} header: {
Text(L10n.Endpoint.Advanced.Openvpn.Sections.Communication.header)
}
}
}
private var communicationEditableSection: some View {
Section(
header: Text(L10n.Endpoint.Advanced.Openvpn.Sections.Communication.header)
) {
Section {
themeTextPicker(
L10n.Endpoint.Advanced.Openvpn.Items.Cipher.caption,
selection: $builder.cipher ?? OpenVPN.Configuration.Fallback.cipher,
@ -150,14 +148,14 @@ extension EndpointAdvancedView.OpenVPNView {
Text(Unlocalized.VPN.xor)
.withTrailingText($0.localizedDescriptionAsXOR)
}
} header: {
Text(L10n.Endpoint.Advanced.Openvpn.Sections.Communication.header)
}
}
private func compressionSection(configuration: OpenVPN.Configuration) -> some View {
configuration.compressionSettings.map { settings in
Section(
header: Text(L10n.Endpoint.Advanced.Openvpn.Sections.Compression.header)
) {
Section {
settings.framing.map {
Text(L10n.Endpoint.Advanced.Openvpn.Items.CompressionFraming.caption)
.withTrailingText($0.localizedDescription)
@ -166,14 +164,14 @@ extension EndpointAdvancedView.OpenVPNView {
Text(L10n.Endpoint.Advanced.Openvpn.Items.CompressionAlgorithm.caption)
.withTrailingText($0.localizedDescription)
}
} header: {
Text(L10n.Endpoint.Advanced.Openvpn.Sections.Compression.header)
}
}
}
private var compressionEditableSection: some View {
Section(
header: Text(L10n.Endpoint.Advanced.Openvpn.Sections.Compression.header)
) {
Section {
themeTextPicker(
L10n.Endpoint.Advanced.Openvpn.Items.CompressionFraming.caption,
selection: $builder.compressionFraming ?? OpenVPN.Configuration.Fallback.compressionFraming,
@ -186,14 +184,14 @@ extension EndpointAdvancedView.OpenVPNView {
values: OpenVPN.CompressionAlgorithm.available,
description: \.localizedDescription
).disabled(builder.compressionFraming == .disabled)
} header: {
Text(L10n.Endpoint.Advanced.Openvpn.Sections.Compression.header)
}
}
private func dnsSection(configuration: OpenVPN.Configuration) -> some View {
configuration.dnsSettings.map { settings in
Section(
header: Text(Unlocalized.Network.dns)
) {
Section {
ForEach(settings.servers, id: \.self) {
Text(L10n.Global.Strings.address)
.withTrailingText($0, copyOnTap: true)
@ -202,15 +200,15 @@ extension EndpointAdvancedView.OpenVPNView {
Text(L10n.Global.Strings.domain)
.withTrailingText($0, copyOnTap: true)
}
} header: {
Text(Unlocalized.Network.dns)
}
}
}
private func proxySection(configuration: OpenVPN.Configuration) -> some View {
configuration.proxySettings.map { settings in
Section(
header: Text(L10n.Global.Strings.proxy)
) {
Section {
settings.proxy.map {
Text(L10n.Global.Strings.address)
.withTrailingText($0.rawValue, copyOnTap: true)
@ -223,14 +221,14 @@ extension EndpointAdvancedView.OpenVPNView {
Text(L10n.NetworkSettings.Items.ProxyBypass.caption)
.withTrailingText($0, copyOnTap: true)
}
} header: {
Text(L10n.Global.Strings.proxy)
}
}
}
private var tlsSection: some View {
Section(
header: Text(Unlocalized.Network.tls)
) {
Section {
builder.ca.map { ca in
themeLongContentLink(
Unlocalized.VPN.certificateAuthority,
@ -258,14 +256,14 @@ extension EndpointAdvancedView.OpenVPNView {
}
Text(L10n.Endpoint.Advanced.Openvpn.Items.Eku.caption)
.withTrailingText(builder.checksEKU.localizedDescriptionAsEKU)
} header: {
Text(Unlocalized.Network.tls)
}
}
private func otherSection(configuration: OpenVPN.Configuration) -> some View {
configuration.otherSettings.map { settings in
Section(
header: Text(L10n.Endpoint.Advanced.Openvpn.Sections.Other.header)
) {
Section {
settings.keepAlive.map {
Text(L10n.Global.Strings.keepalive)
.withTrailingText($0.localizedDescriptionAsKeepAlive)
@ -278,6 +276,8 @@ extension EndpointAdvancedView.OpenVPNView {
Text(L10n.Endpoint.Advanced.Openvpn.Items.RandomEndpoint.caption)
.withTrailingText($0.localizedDescriptionAsRandomizeEndpoint)
}
} header: {
Text(L10n.Endpoint.Advanced.Openvpn.Sections.Other.header)
}
}
}

View File

@ -46,27 +46,25 @@ extension EndpointAdvancedView {
extension EndpointAdvancedView.WireGuardView {
private var keySection: some View {
Section(
header: Text(L10n.Global.Strings.interface)
) {
Section {
themeLongContentLink(L10n.Global.Strings.privateKey, content: .constant(builder.privateKey))
themeLongContentLink(L10n.Global.Strings.publicKey, content: .constant(builder.publicKey))
} header: {
Text(L10n.Global.Strings.interface)
}
}
private var addressesSection: some View {
Section(
header: Text(L10n.Global.Strings.addresses)
) {
Section {
ForEach(builder.addresses, id: \.self, content: Text.init)
} header: {
Text(L10n.Global.Strings.addresses)
}
}
private func dnsSection(configuration: WireGuard.Configuration) -> some View {
configuration.dnsSettings.map { settings in
Section(
header: Text(Unlocalized.Network.dns)
) {
Section {
ForEach(settings.servers, id: \.self) {
Text(L10n.Global.Strings.address)
.withTrailingText($0)
@ -75,6 +73,8 @@ extension EndpointAdvancedView.WireGuardView {
Text(L10n.Global.Strings.domain)
.withTrailingText($0)
}
} header: {
Text(Unlocalized.Network.dns)
}
}
}

View File

@ -154,12 +154,12 @@ extension EndpointView.OpenVPNView {
}
private var addressesSection: some View {
Section(
header: Text(L10n.Global.Strings.addresses)
) {
Section {
filteredRemotes.map {
ForEach($0, content: button(forEndpoint:))
}
} header: {
Text(L10n.Global.Strings.addresses)
}
}

View File

@ -104,9 +104,7 @@ extension EndpointView.WireGuardView {
}
private func section(forPeerAt peerIndex: Int) -> some View {
Section(
header: Text(L10n.Endpoint.Wireguard.Items.Peer.caption)
) {
Section {
themeLongContentLink(
L10n.Global.Strings.publicKey,
content: .constant(builder.publicKey(ofPeer: peerIndex))
@ -129,6 +127,8 @@ extension EndpointView.WireGuardView {
Text(L10n.Global.Strings.keepalive)
.withTrailingText(TimeInterval($0).localizedDescriptionAsKeepAlive)
}
} header: {
Text(L10n.Endpoint.Wireguard.Items.Peer.caption)
}
}

View File

@ -97,15 +97,15 @@ struct NetworkSettingsView: View {
extension NetworkSettingsView {
private var gatewayView: some View {
Section(
header: Text(L10n.NetworkSettings.Gateway.title)
) {
Section {
Toggle(L10n.Global.Strings.automatic, isOn: $settings.isAutomaticGateway.themeAnimation())
if !settings.isAutomaticGateway {
Toggle(Unlocalized.Network.ipv4, isOn: $settings.gateway.isDefaultIPv4)
Toggle(Unlocalized.Network.ipv6, isOn: $settings.gateway.isDefaultIPv6)
}
} header: {
Text(L10n.NetworkSettings.Gateway.title)
}
}
}
@ -116,9 +116,7 @@ extension NetworkSettingsView {
@ViewBuilder
private var dnsView: some View {
Section(
header: Text(Unlocalized.Network.dns)
) {
Section {
Toggle(L10n.Global.Strings.automatic, isOn: $settings.isAutomaticDNS.themeAnimation())
if !settings.isAutomaticDNS {
@ -143,6 +141,8 @@ extension NetworkSettingsView {
EmptyView()
}
}
} header: {
Text(Unlocalized.Network.dns)
}
if !settings.isAutomaticDNS && settings.dns.configurationType != .disabled {
dnsManualServers
@ -209,9 +209,7 @@ extension NetworkSettingsView {
@ViewBuilder
private var proxyView: some View {
Section(
header: Text(L10n.Global.Strings.proxy)
) {
Section {
Toggle(L10n.Global.Strings.automatic, isOn: $settings.isAutomaticProxy.themeAnimation())
if !settings.isAutomaticProxy {
@ -240,6 +238,8 @@ extension NetworkSettingsView {
EmptyView()
}
}
} header: {
Text(L10n.Global.Strings.proxy)
}
if !settings.isAutomaticProxy && settings.proxy.configurationType == .manual {
proxyManualBypassDomains
@ -272,9 +272,7 @@ extension NetworkSettingsView {
extension NetworkSettingsView {
private var mtuView: some View {
Section(
header: Text(Unlocalized.Network.mtu)
) {
Section {
Toggle(L10n.Global.Strings.automatic, isOn: $settings.isAutomaticMTU.themeAnimation())
if !settings.isAutomaticMTU {
@ -285,6 +283,8 @@ extension NetworkSettingsView {
description: \.localizedDescriptionAsMTU
)
}
} header: {
Text(Unlocalized.Network.mtu)
}
}
}

View File

@ -79,27 +79,27 @@ extension OnDemandView {
@ViewBuilder
private var mainView: some View {
if Utils.hasCellularData() {
Section(
// TODO: on-demand, restore when "trusted networks" -> "on-demand"
// header: Text(L10n.Profile.Sections.Trusted.header)
) {
Section {
Toggle(L10n.OnDemand.Items.Mobile.caption, isOn: $onDemand.withMobileNetwork)
} header: {
// TODO: on-demand, restore when "trusted networks" -> "on-demand"
// Text(L10n.Profile.Sections.Trusted.header)
}
Section {
SSIDList(withSSIDs: $onDemand.withSSIDs)
}
} else {
Section(
// TODO: on-demand, restore when "trusted networks" -> "on-demand"
// header: Text(L10n.Profile.Sections.Trusted.header)
) {
Section {
SSIDList(withSSIDs: $onDemand.withSSIDs)
} header: {
// TODO: on-demand, restore when "trusted networks" -> "on-demand"
// Text(L10n.Profile.Sections.Trusted.header)
}
}
Section(
footer: Text(L10n.OnDemand.Sections.Policy.footer)
) {
Section {
Toggle(L10n.OnDemand.Items.Policy.caption, isOn: $onDemand.disconnectsIfNotMatching)
} footer: {
Text(L10n.OnDemand.Sections.Policy.footer)
}
}

View File

@ -109,16 +109,17 @@ extension PaywallView {
}
private var productsSection: some View {
Section(
header: Text(L10n.Paywall.title),
footer: Text(L10n.Paywall.Sections.Products.footer)
) {
Section {
if !productManager.isRefreshingProducts {
ForEach(productRowModels, id: \.product.productIdentifier, content: productRow)
} else {
ProgressView()
}
restoreRow
} header: {
Text(L10n.Paywall.title)
} footer: {
Text(L10n.Paywall.Sections.Products.footer)
}
}

View File

@ -49,9 +49,7 @@ extension ProfileView {
}
var body: some View {
Section(
header: Text(L10n.Global.Strings.configuration)
) {
Section {
if currentProfile.value.vpnProtocols.count > 1 {
themeTextPicker(
L10n.Global.Strings.protocol,
@ -109,6 +107,8 @@ extension ProfileView {
onDemandRow
}
}
} header: {
Text(L10n.Global.Strings.configuration)
}
}

View File

@ -52,9 +52,7 @@ extension ProfileView {
}
var body: some View {
Section(
header: Text(L10n.Profile.Sections.Feedback.header)
) {
Section {
if isActiveProfile {
NavigationLink {
DiagnosticsView(
@ -70,6 +68,8 @@ extension ProfileView {
} label: {
Label(Unlocalized.About.faq, systemImage: themeFAQImage)
}
} header: {
Text(L10n.Profile.Sections.Feedback.header)
}
}
}

View File

@ -36,22 +36,22 @@ extension ProfileView {
var body: some View {
if currentProfile.value.isProvider {
Section(
footer: Text(L10n.Profile.Sections.VpnResolvesHostname.footer)
) {
Section {
Toggle(
L10n.Profile.Items.VpnResolvesHostname.caption,
isOn: $currentProfile.value.networkSettings.resolvesHostname
)
} footer: {
Text(L10n.Profile.Sections.VpnResolvesHostname.footer)
}
}
Section(
footer: Text(L10n.Profile.Sections.VpnSurvivesSleep.footer)
) {
Section {
Toggle(
L10n.Profile.Items.VpnSurvivesSleep.caption,
isOn: $currentProfile.value.networkSettings.keepsAliveOnSleep
)
} footer: {
Text(L10n.Profile.Sections.VpnSurvivesSleep.footer)
}
}
}

View File

@ -57,12 +57,7 @@ extension ProfileView {
}
private var mainView: some View {
Section(
header: Text(currentProvider.fullName),
footer: lastInfrastructureUpdate.map {
Text(L10n.Profile.Sections.ProviderInfrastructure.footer($0))
}
) {
Section {
NavigationLink(isActive: $isProviderLocationPresented) {
ProviderLocationView(
currentProfile: currentProfile,
@ -85,6 +80,12 @@ extension ProfileView {
Button(action: refreshInfrastructure) {
Text(L10n.Profile.Items.Provider.Refresh.caption)
}.withTrailingProgress(when: isRefreshingInfrastructure)
} header: {
Text(currentProvider.fullName)
} footer: {
lastInfrastructureUpdate.map {
Text(L10n.Profile.Sections.ProviderInfrastructure.footer($0))
}
}
}

View File

@ -45,12 +45,12 @@ extension ProfileView {
var body: some View {
List {
Section(
header: Text(L10n.Profile.Alerts.Rename.title)
) {
Section {
TextField(L10n.Global.Placeholders.profileName, text: $newName, onCommit: commitRenaming)
.themeValidProfileName()
.onAppear(perform: loadCurrentName)
} header: {
Text(L10n.Profile.Alerts.Rename.title)
}
}.themeSecondaryView()
.navigationTitle(currentProfile.value.header.name)

View File

@ -80,11 +80,7 @@ extension ProfileView {
}
private var activeView: some View {
Section(
header: headerView,
footer: Text(L10n.Profile.Sections.Vpn.footer)
.xxxThemeTruncation()
) {
Section {
VPNToggle(rateLimit: Constants.RateLimit.vpnToggle) {
// eligibility: donate intents if eligible for Siri
@ -105,13 +101,16 @@ extension ProfileView {
withErrors: true,
dataCountIfAvailable: true
))
} header: {
headerView
} footer: {
Text(L10n.Profile.Sections.Vpn.footer)
.xxxThemeTruncation()
}
}
private var inactiveSubview: some View {
Section(
header: headerView
) {
Section {
Button(L10n.Profile.Items.UseProfile.caption) {
Task {
@ -127,14 +126,16 @@ extension ProfileView {
}
}
}
} header: {
headerView
}
}
private var loadingView: some View {
Section(
header: headerView
) {
Section {
ProgressView()
} header: {
headerView
}
}
}

View File

@ -134,9 +134,7 @@ struct ProviderLocationView: View, ProviderProfileAvailability {
}
private func categorySection(_ category: ProviderCategory) -> some View {
Section(
header: !category.name.isEmpty ? Text(category.name) : nil
) {
Section {
ForEach(filteredLocations(for: category)) { location in
if isEditable, #available(iOS 15, *) {
locationRow(location)
@ -147,6 +145,8 @@ struct ProviderLocationView: View, ProviderProfileAvailability {
locationRow(location)
}
}
} header: {
!category.name.isEmpty ? Text(category.name) : nil
}
}
@ -185,9 +185,9 @@ struct ProviderLocationView: View, ProviderProfileAvailability {
}
private var emptyFavoritesSection: some View {
Section(
footer: Text(L10n.Provider.Location.Sections.EmptyFavorites.footer)
) {
Section {
} footer: {
Text(L10n.Provider.Location.Sections.EmptyFavorites.footer)
}
}

View File

@ -69,9 +69,7 @@ struct ProviderPresetView: View {
}
private func presetSection(_ preset: ProviderServer.Preset) -> some View {
Section(
header: Text(preset.name)
) {
Section {
Button {
selectedPreset = preset
presentationMode.wrappedValue.dismiss()
@ -89,6 +87,8 @@ struct ProviderPresetView: View {
).navigationTitle(preset.name)
}
}
} header: {
Text(preset.name)
}
}

View File

@ -49,24 +49,24 @@ extension ShortcutsView {
ZStack {
hiddenProviderLocationLink
List {
Section(
header: Text(Unlocalized.VPN.vpn)
) {
Section {
addConnectView
Button(L10n.Shortcuts.Add.Items.EnableVpn.caption, action: addEnableVPN)
Button(L10n.Shortcuts.Add.Items.DisableVpn.caption, action: addDisableVPN)
} header: {
Text(Unlocalized.VPN.vpn)
}
Section(
header: Text(L10n.Shortcuts.Add.Sections.Wifi.header)
) {
Section {
Button(L10n.Shortcuts.Add.Items.TrustCurrentWifi.caption, action: addTrustWiFi)
Button(L10n.Shortcuts.Add.Items.UntrustCurrentWifi.caption, action: addUntrustWiFi)
} header: {
Text(L10n.Shortcuts.Add.Sections.Wifi.header)
}
Section(
header: Text(L10n.Shortcuts.Add.Sections.Cellular.header)
) {
Section {
Button(L10n.Shortcuts.Add.Items.TrustCellular.caption, action: addTrustCellular)
Button(L10n.Shortcuts.Add.Items.UntrustCellular.caption, action: addUntrustCellular)
} header: {
Text(L10n.Shortcuts.Add.Sections.Cellular.header)
}
}
}.navigationTitle(L10n.Shortcuts.Add.title)

View File

@ -85,10 +85,10 @@ struct ShortcutsView: View {
}
private var shortcutsSection: some View {
Section(
header: Text(L10n.Shortcuts.Edit.Sections.All.header)
) {
Section {
ForEach(relevantShortcuts, content: rowView)
} header: {
Text(L10n.Shortcuts.Edit.Sections.All.header)
}
}
@ -99,9 +99,7 @@ struct ShortcutsView: View {
}
private var addSection: some View {
Section(
footer: Text(L10n.Shortcuts.Edit.Sections.Add.footer)
) {
Section {
NavigationLink(isActive: $isNavigationPresented) {
AddView(
target: target,
@ -110,6 +108,8 @@ struct ShortcutsView: View {
} label: {
Text(L10n.Shortcuts.Edit.Items.AddShortcut.caption)
}
} footer: {
Text(L10n.Shortcuts.Edit.Sections.Add.footer)
}
}