"?"-Hilfe-Buttons in allen 6 Haupt-Tabs, allen 6 Wizard-Schritten und allen 45 Experte-Menüs öffnen ein Handbuch-Fenster (WKWebView) und springen per Textanker direkt zur passenden Manual-Stelle. build-manual.py generalisiert auf beliebig viele Sprachen (LANGUAGES- Dict) statt hart DE/EN. Manual.en.md: komplette Handübersetzung aller Fließtext-Kapitel. Kapitel 5 (Experte-Referenz) wird pro Sprache automatisch übersetzt, indem L10n.swifts eigenes App-Übersetzungs- Dictionary wiederverwendet wird (714 Einträge geparst) statt einer zweiten, separat gepflegten Übersetzung. Live bestätigt (DE und EN). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
72 lines
3.7 KiB
Swift
72 lines
3.7 KiB
Swift
import SwiftUI
|
|
|
|
struct FirewallStepView: View {
|
|
@ObservedObject var viewModel: SetupViewModel
|
|
@AppStorage("appLanguage") private var appLanguage: String = "de"
|
|
|
|
var body: some View {
|
|
Form {
|
|
Section {
|
|
if viewModel.mode == .expert {
|
|
Toggle(
|
|
L10n.t("Firewall-Grundschutz einrichten (empfohlen)", appLanguage),
|
|
isOn: Binding(
|
|
get: { viewModel.firewallSectionEnabled },
|
|
set: { viewModel.setFirewallSectionEnabled($0) }
|
|
)
|
|
)
|
|
.help(L10n.t("Schützt deinen Router und deine Geräte vor unaufgeforderten Zugriffen aus dem Internet und ermöglicht deinen Geräten den Internetzugriff (NAT).", appLanguage))
|
|
} else {
|
|
Text(L10n.t("Firewall-Grundschutz ist im einfachen Modus immer aktiv.", appLanguage))
|
|
}
|
|
Text(L10n.t("Richtet einen Standard-Schutz ein: Internetfreigabe (NAT) für dein Heimnetz, und blockiert unaufgeforderte Zugriffe aus dem Internet auf deinen Router und deine Geräte. Bestehende, selbst eingerichtete Regeln bleiben erhalten — die neuen Regeln werden vorangestellt.", appLanguage))
|
|
.appFont(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
|
|
if viewModel.firewallSectionEnabled {
|
|
Section(L10n.t("Bereits vorhandene Regeln", appLanguage)) {
|
|
if viewModel.isLoadingFirewallRuleCounts {
|
|
ProgressView()
|
|
} else if let counts = viewModel.existingFirewallRuleCounts {
|
|
LabeledContent(L10n.t("Filter-Regeln", appLanguage), value: "\(counts.filterRuleCount)")
|
|
LabeledContent(L10n.t("NAT-Regeln", appLanguage), value: "\(counts.natRuleCount)")
|
|
if counts.filterRuleCount > 0 || counts.natRuleCount > 0 {
|
|
Text(L10n.t("Dein Router hat bereits eigene Firewall-Regeln. Die neuen Regeln werden vorangestellt, bestehende bleiben erhalten — prüfe nach dem Anwenden trotzdem die Reihenfolge, z.B. über Winbox oder \"/ip firewall filter print\".", appLanguage))
|
|
.appFont(.caption)
|
|
.foregroundStyle(.orange)
|
|
}
|
|
} else if let error = viewModel.firewallRuleCountsError {
|
|
Text(error).appFont(.caption).foregroundStyle(.red)
|
|
}
|
|
}
|
|
}
|
|
|
|
if !viewModel.isolatedNetworkNames.isEmpty {
|
|
Section(L10n.t("Isolierte Netzwerke", appLanguage)) {
|
|
Text(viewModel.isolatedNetworkNames.joined(separator: ", "))
|
|
Text(L10n.t("Diese Netzwerke werden vom Datenverkehr aller anderen konfigurierten Netzwerke abgeschottet, sobald der Firewall-Grundschutz aktiv ist.", appLanguage))
|
|
.appFont(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
|
|
Section {
|
|
HStack {
|
|
Button(L10n.t("Zurück", appLanguage)) { viewModel.goBack() }
|
|
Spacer()
|
|
Button(L10n.t("Weiter", appLanguage)) { viewModel.goNext() }
|
|
}
|
|
}
|
|
}
|
|
.formStyle(.grouped)
|
|
.navigationTitle(LocalizedStringKey(L10n.t("Firewall (optional)", appLanguage)))
|
|
.toolbar { ToolbarItem { ManualHelpButton(anchor: ManualAnchor.stepFirewall) } }
|
|
.onAppear {
|
|
if viewModel.firewallSectionEnabled {
|
|
viewModel.loadExistingFirewallRuleCounts()
|
|
}
|
|
}
|
|
}
|
|
}
|