UI-Rework: Bereichs-Navigation statt Interview (Loesung A, #72)
Build / build (push) Canceled after 0s
Build / build (push) Canceled after 0s
- Seitenleiste mit Verbindungskarte und frei anklickbaren Bereichen Start, Einrichten, Uebersicht, Geraete, Backup & Wartung, Experte; Hilfe & Begriffe und Einstellungen als Bereiche unten (vorher Fenster) - Ohne Verbindung: Verbinden-Seite, Geraetebereiche gesperrt - Einrichten: Assistent mit anklickbaren Schritten und eigener Zurueck/Weiter-Leiste (SetupWizardViewModel) - Start: Schnellzugriffe, Geraetedaten, RouterOS-Update - Bereichswahl-Schritt und SelectedArea entfallen; Plan wird bei jedem neuen Verbinden zurueckgesetzt (WizardSession.ResetPlan) - Fix: Entfernen eines bekannten Routers in der Seitenleiste band an ein nicht vorhandenes Kommando Closes #72 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c8348640f8
commit
f2dd7e790e
40 files changed
+810
-706
No files matched your search
@@ -3,29 +3,42 @@
|
||||
[](LICENSE)
|
||||
[](../../releases)
|
||||
|
||||
Ein Windows-Programm, mit dem sich MikroTik-Router/-Switches in wenigen, klar geführten Schritten einrichten lassen – auch ohne Netzwerk-Vorkenntnisse. Statt WinBox-Menüs und RouterOS-Fachbegriffen gibt es ein Interview: Verbindung herstellen, ein paar verständliche Fragen beantworten, fertig.
|
||||
Ein Windows-Programm, mit dem sich MikroTik-Router/-Switches in wenigen, klar geführten Schritten einrichten lassen – auch ohne Netzwerk-Vorkenntnisse. Statt WinBox-Menüs und RouterOS-Fachbegriffen gibt es frei anklickbare Bereiche und einen geführten Einrichtungs-Assistenten: Verbindung herstellen, ein paar verständliche Fragen beantworten, fertig.
|
||||
|
||||
> **Hinweis:** Dies ist ein unabhängiges, privates Open-Source-Projekt ohne jede kommerzielle Absicht. Es steht in keiner Verbindung zu MikroTik und wird nicht von MikroTik unterstützt, gesponsert oder geprüft. Siehe [Markenrechte & Haftungsausschluss](#markenrechte--haftungsausschluss).
|
||||
|
||||

|
||||
|
||||
## Bedienung: Bereiche statt Interview
|
||||
|
||||
Die Seitenleiste zeigt oben die Verbindung (bekannte Router zum Anklicken bzw. das verbundene Gerät mit „Wechseln"), darunter die **frei anklickbaren Bereiche** wie in der Mac-Version; unten stehen „Hilfe & Begriffe" und „Einstellungen". Ohne Verbindung zeigt der Inhalt die Verbinden-Seite, und die Gerätebereiche sind gesperrt; Hilfe und Einstellungen gehen immer.
|
||||
|
||||
| Bereich | Inhalt |
|
||||
|---|---|
|
||||
| **Start** | Schnellzugriffe, Gerätedaten (Modell, RouterOS-Version, Seriennummer, Schnittstellen mit Link-Status-Punkt) und RouterOS-Update |
|
||||
| **Einrichten** | der Einrichtungs-Assistent (siehe unten), Schritte oben direkt anklickbar, eigene Zurück/Weiter-Leiste |
|
||||
| **Übersicht** | nach Kategorien gruppierte, anklickbare Grafik der vorhandenen Bridges, VLANs, IP-Adressen, DHCP-Server, WLANs und IP-gebundenen Firewall-/NAT-Regeln, mit „Professioneller Netzwerker" direkt bearbeitbar |
|
||||
| **Geräte** | LAN-Scanner: alle erkannten Geräte nach Anschluss gruppiert, feste IP zuweisen, Werkzeuge (siehe unten) |
|
||||
| **Backup & Wartung** | Backups, Neustart, Firmware, Werksreset (siehe unten) |
|
||||
| **Experte** | nur mit „Professioneller Netzwerker": RouterOS-Menüs und Werkzeuge (siehe unten) |
|
||||
|
||||
Nach dem Verbinden liest die App das Gerät einmal aus, trägt es in „Bekannte Router" ein und öffnet „Start". Bei jedem neuen Verbinden beginnt der Einrichtungsplan von vorn, damit nichts vom vorherigen Gerät angewendet wird. Ein erneuter Klick auf einen Bereich lädt ihn neu.
|
||||
|
||||
## Was der Assistent einrichtet
|
||||
|
||||
Schritt für Schritt, mit Erklär-Tooltips (ⓘ) bei jedem Fachbegriff:
|
||||
Im Bereich „Einrichten", mit Erklär-Tooltips (ⓘ) bei jedem Fachbegriff. Die Schritte lassen sich in beliebiger Reihenfolge anklicken; besuchte Schritte bekommen einen Haken. Die Zusammenfassung enthält nur, was in besuchten Schritten gültig eingestellt wurde.
|
||||
|
||||
1. **Verbindung** – IP-Adresse, Benutzername, Passwort (optional „Passwort merken"); **„Router im Netzwerk suchen"** findet MikroTik-Geräte per MNDP auch ohne passende IP (siehe unten); bereits erfolgreich verbundene Geräte erscheinen als **„Bekannte Router"** in der Sidebar; die **Testumgebung** bietet simulierte Router ohne eigene Hardware
|
||||
2. **Was möchtest du tun?** – Weiche direkt nach dem Verbinden: kompletter Einrichtungs-Assistent (Standard), direkt zu **„Backup & Wartung"** oder — nur mit „Professioneller Netzwerker" — in den Bereich **„Experte"** (siehe unten); die beiden Letzteren überspringen den restlichen Assistenten
|
||||
3. **Geräte-Erkennung** – liest Modell, RouterOS-Version, Seriennummer und Schnittstellen (mit Link-Status-Punkt) aus
|
||||
4. **Vorhandene Netzwerke** – bei einem Bestandsgerät: nach Kategorien gruppierte, anklickbare Grafik der bereits eingerichteten Bridges, VLANs, IP-Adressen, DHCP-Server, WLANs und IP-gebundenen Firewall-/NAT-Regeln (siehe unten), mit „Professioneller Netzwerker" direkt bearbeitbar; bei werksneuen Geräten erscheint nur ein kurzer Hinweis
|
||||
5. **Geräte im Netzwerk** – nach Anschluss gruppierte Liste aller aktuell erkannten Geräte (aus DHCP-Leases, ARP- und Bridge-Host-Tabelle zusammengeführt), mit der Möglichkeit, einem Gerät direkt eine feste IP-Adresse zuzuweisen oder das wieder rückgängig zu machen (siehe unten)
|
||||
6. **Modus wählen** *(nur mit „Professioneller Netzwerker" in den Einstellungen)* – geführter Assistent (Standard) oder **Experten-Modus**: Letzterer blendet in den folgenden Schritten zusätzliche, technischere RouterOS-Optionen ein (siehe unten)
|
||||
7. **Internet-Zugang** – WAN-Schnittstelle, DHCP oder feste IP, NAT
|
||||
8. **Heimnetzwerk (DHCP)** – Bridge, IP-Bereich, DHCP-Server, DNS; vorbelegt mit dem schon vorhandenen Heimnetz des Routers, „Port freimachen?" bei belegten Anschlüssen, Lease-Zeit als Jahre/Tage/Stunden
|
||||
9. **VLANs** *(optional)* – zusätzliche, getrennte Netzwerke (z. B. Gäste, IoT), im Experten-Modus wahlweise fest einem oder mehreren Anschlüssen zugeordnet (portbasiert, siehe unten)
|
||||
10. **WLAN** *(übersprungen, wenn nicht vorhanden – oder bewusst abwählbar, z. B. bei einem reinen Switch)*
|
||||
11. **Firewall** – sichere Basisregeln, optionale Portfreigaben
|
||||
12. **Zusammenfassung** – alle geplanten Änderungen im Klartext, automatisches Backup auf dem Gerät vor dem Anwenden (eigener, sichtbarer Schritt), Fortschrittsbalken und Abschluss-Übersicht, **PDF-Export** mit allen Zugangsdaten inkl. WLAN-QR-Code zum Ausdrucken/Aufbewahren
|
||||
13. **RouterOS-Update** *(optional)* – prüft auf eine neuere RouterOS-Version und kann sie mit deutlicher Warnung starten
|
||||
Verbunden wird vorher auf der Verbinden-Seite: IP-Adresse, Benutzername, Passwort (optional „Passwort merken"); **„Router im Netzwerk suchen"** findet MikroTik-Geräte per MNDP auch ohne passende IP (siehe unten); bereits erfolgreich verbundene Geräte erscheinen als **„Bekannte Router"** in der Seitenleiste; die **Testumgebung** bietet simulierte Router ohne eigene Hardware.
|
||||
|
||||
1. **Modus wählen** *(nur mit „Professioneller Netzwerker" in den Einstellungen)* – geführter Assistent (Standard) oder **Experten-Modus**: Letzterer blendet in den folgenden Schritten zusätzliche, technischere RouterOS-Optionen ein (siehe unten)
|
||||
2. **Internet-Zugang** – WAN-Schnittstelle, DHCP oder feste IP, NAT
|
||||
3. **Heimnetzwerk (DHCP)** – Bridge, IP-Bereich, DHCP-Server, DNS; vorbelegt mit dem schon vorhandenen Heimnetz des Routers, „Port freimachen?" bei belegten Anschlüssen, Lease-Zeit als Jahre/Tage/Stunden
|
||||
4. **VLANs** *(optional)* – zusätzliche, getrennte Netzwerke (z. B. Gäste, IoT), im Experten-Modus wahlweise fest einem oder mehreren Anschlüssen zugeordnet (portbasiert, siehe unten)
|
||||
5. **WLAN** *(übersprungen, wenn nicht vorhanden – oder bewusst abwählbar, z. B. bei einem reinen Switch)*
|
||||
6. **Firewall** – sichere Basisregeln, optionale Portfreigaben
|
||||
7. **Zusammenfassung** – alle geplanten Änderungen im Klartext, automatisches Backup auf dem Gerät vor dem Anwenden (eigener, sichtbarer Schritt), Fortschrittsbalken und Abschluss-Übersicht, **PDF-Export** mit allen Zugangsdaten inkl. WLAN-QR-Code zum Ausdrucken/Aufbewahren
|
||||
|
||||
Das **RouterOS-Update** steht auf der Startseite: Es prüft auf eine neuere RouterOS-Version und kann sie mit deutlicher Warnung starten.
|
||||
|
||||
Nichts wird am Gerät verändert, bevor der Nutzer in der Zusammenfassung ausdrücklich auf „Jetzt einrichten“ klickt (Ausnahmen: die ausdrücklichen Aktionen in „Backup & Wartung“ und „Feste IP zuweisen“ im LAN-Scanner, siehe unten).
|
||||
|
||||
@@ -61,13 +74,13 @@ Wer RouterOS kennt, kann im vierten Schritt den Experten-Modus wählen. Die Schr
|
||||
|
||||
### Backup & Wartung
|
||||
|
||||
Eigenständiger Bereich, erreichbar direkt im zweiten Schritt („Was möchtest du tun?") — ohne den restlichen Einrichtungs-Assistenten zu durchlaufen. Liest das verbundene Gerät selbst aus und zeigt sofort: vorhandene Backups auf dem Gerät (nach Tag gruppiert), einen „Neues Backup erstellen"-Button für eine frische, unabhängige Sicherung (z. B. vor eigenen Änderungen direkt in WinBox — erscheint sofort in der Liste) und „Aktualisieren" zum erneuten Auflisten. Ein Backup lässt sich direkt aus der Liste zurückspielen.
|
||||
Eigenständiger Bereich in der Seitenleiste. Liest das verbundene Gerät selbst aus und zeigt sofort: vorhandene Backups auf dem Gerät (nach Tag gruppiert), einen „Neues Backup erstellen"-Button für eine frische, unabhängige Sicherung (z. B. vor eigenen Änderungen direkt in WinBox — erscheint sofort in der Liste) und „Aktualisieren" zum erneuten Auflisten. Ein Backup lässt sich direkt aus der Liste zurückspielen.
|
||||
|
||||
- **Verschlüsselung:** Ist in den Einstellungen ein Backup-Passwort gesetzt, verschlüsselt RouterOS jedes neue Backup selbst (`password=…`, `encryption=aes-sha256`); der Dateiname bekommt die Endung `-enc`, die Liste zeigt ein Schloss, und beim Zurückspielen wird das Passwort mitgegeben. Ohne Passwort weist der Bereich darauf hin, dass Backups unverschlüsselt entstehen. Das Passwort liegt im Windows-Anmeldeinformationsspeicher.
|
||||
- **Auf PC speichern:** lädt das ausgewählte Backup per SFTP (SSH-Dienst des Routers) in den Backup-Ordner aus den Einstellungen. Beim ersten Mal wird der SSH-Schlüssel des Routers bestätigt und gemerkt (TOFU, `%AppData%\MikroTik-Installer\known-hosts.json`); ein geänderter Schlüssel wird nie still akzeptiert.
|
||||
- **Handsicherung zählt:** Ein von Hand erstelltes Backup ersetzt 10 Minuten lang die automatische Sicherung vor der nächsten Änderung (Anwenden, Zurückspielen, Werksreset) — kein Backup-Stapel für jeden Handgriff.
|
||||
- **Wartung:** „Jetzt neu starten"; bei RouterBOARD-Hardware die installierte und die mitgelieferte **Firmware** mit „Firmware aktualisieren und neu starten"; als Notfallschalter **„Auf Werkseinstellungen zurücksetzen"** (nur nach Bestätigung, vorher eigene Sicherung, RouterOS legt zusätzlich selbst eine an; danach ist das Gerät meist unter `192.168.88.1` erreichbar, die Verbindung wird beendet).
|
||||
- **Automatisches Wiederverbinden:** Nach Neustart, Firmware-Update, Zurückspielen und RouterOS-Update wartet der Assistent, bis das Gerät wieder antwortet (alle 5 s ein Versuch, Zähler in der Sidebar, Aufgabe nach etwa 5 Minuten) und liest danach alles neu ein. Zusätzlich prüft ein Herzschlag alle 30 s bei aktivem Fenster, ob die Verbindung noch steht, und verbindet bei einem Abbruch selbst neu.
|
||||
- **Automatisches Wiederverbinden:** Nach Neustart, Firmware-Update, Zurückspielen und RouterOS-Update wartet der Assistent, bis das Gerät wieder antwortet (alle 5 s ein Versuch, Zähler in der Seitenleiste, Aufgabe nach etwa 5 Minuten) und liest danach alles neu ein. Zusätzlich prüft ein Herzschlag alle 30 s bei aktivem Fenster, ob die Verbindung noch steht, und verbindet bei einem Abbruch selbst neu.
|
||||
|
||||
RouterOS prüft beim Zurückspielen selbst nicht, ob ein Backup zum verbundenen Gerät passt — es importiert klaglos eine Fremd-Konfiguration mit ggf. falsch zugeordneten Interfaces. Der Assistent verhindert das mit einer vierstufigen Prüfung: Jedes hier selbst erstellte Backup trägt Gerätemodell, Architektur **und Seriennummer** im Dateinamen (z. B. `mikrotik-installer-RB750Gr3_arm_414403A029A5-20260917-193000.backup`, jeweils per `_` getrennt).
|
||||
|
||||
@@ -97,7 +110,7 @@ Fehlt ein Bereich, weil er ein eigenes Paket ist (z. B. Hotspot auf dem hAP lite
|
||||
|
||||
### Hilfe & Begriffe
|
||||
|
||||
„Hilfe & Begriffe" in der Seitenleiste öffnet ein Fenster mit dem Handbuch ([`docs/Handbuch.md`](docs/Handbuch.md), in die App eingebettet) und 49 durchsuchbaren Begriffserklärungen (aus dem Glossar der Mac-Version übernommen und an die Windows-Version angepasst, in Deutsch, Englisch und Portugiesisch hinterlegt).
|
||||
„Hilfe & Begriffe" unten in der Seitenleiste zeigt das Handbuch ([`docs/Handbuch.md`](docs/Handbuch.md), in die App eingebettet) und 49 durchsuchbaren Begriffserklärungen (aus dem Glossar der Mac-Version übernommen und an die Windows-Version angepasst, in Deutsch, Englisch und Portugiesisch hinterlegt).
|
||||
|
||||
### Sprachen
|
||||
|
||||
@@ -109,7 +122,7 @@ Deutsch, Englisch und Portugiesisch (Brasilien), wählbar in den Einstellungen u
|
||||
|
||||
### Einstellungen
|
||||
|
||||
Erreichbar unten in der Sidebar: Erscheinungsbild (Wie System / Hell / Dunkel), Update-Prüfung beim Verbinden, **„Professioneller Netzwerker"** (blendet den Experten-Modus im Assistenten ein, Standard: aus), „Testumgebung anbieten", Ordner für Backups auf diesem PC, Backup-Passwort und „Einführung beim nächsten Start erneut zeigen". Beim ersten Start erscheint eine kurze **Einführung** mit denselben Grundeinstellungen, bis „Fertig" oder „Überspringen" gedrückt wurde. Die App startet maximiert mit einem kurzen Startbildschirm.
|
||||
Bereich unten in der Seitenleiste, auch ohne Verbindung erreichbar; Änderungen gelten mit „Speichern": Sprache, Erscheinungsbild (Wie System / Hell / Dunkel), Update-Prüfung beim Verbinden, **„Professioneller Netzwerker"** (blendet den Bereich „Experte" und den Experten-Modus im Assistenten ein, Standard: aus), „Testumgebung anbieten", Ordner für Backups auf diesem PC, Backup-Passwort und „Einführung beim nächsten Start erneut zeigen". Beim ersten Start erscheint eine kurze **Einführung** mit denselben Grundeinstellungen, bis „Fertig" oder „Überspringen" gedrückt wurde. Die App startet maximiert mit einem kurzen Startbildschirm.
|
||||
|
||||
### Portbasierte VLANs
|
||||
|
||||
@@ -125,7 +138,7 @@ Adress-, Bereichs- und Portfelder in WAN, Heimnetzwerk, VLANs und Firewall werde
|
||||
|
||||
Nach jeder erfolgreichen Verbindung merkt sich der Assistent Host, Benutzername und (sobald die Geräte-Erkennung gelaufen ist) die Hardware-Bezeichnung als Namensvorschlag — rein lokal, ohne weiteren Geräte-Zugriff. Das Passwort liegt dabei **nicht** in der lokalen Datei, sondern im Windows-Anmeldeinformationsspeicher (Systemsteuerung → Anmeldeinformationsverwaltung).
|
||||
|
||||
Bekannte Router leben ausschließlich als kompakte Kurzauswahl **dauerhaft in der Sidebar**, unabhängig vom aktuellen Schritt — das Hauptfenster selbst (Verbindungs-Schritt) zeigt nur noch das Formular für ein neues, noch unbekanntes Gerät, ohne Dopplung. Ein Klick auf einen Sidebar-Eintrag verbindet direkt (ohne Umweg über das Formular) und springt bei Erfolg automatisch weiter; ein kleines Papierkorb-Symbol entfernt einen Eintrag wieder. Der Name kommt automatisch vom Gerätemodell — eine eigene Umbenennung gibt es bewusst nicht mehr, um die Sidebar kompakt zu halten. Sobald eine Verbindung besteht, zeigt dieselbe Stelle stattdessen Gerätename/-modell (sobald die Geräte-Erkennung gelaufen ist, bis dahin nur die Adresse) mit einem „Wechseln"-Button, um die Verbindung zu trennen und zu einem anderen Gerät zurückzukehren.
|
||||
Bekannte Router leben ausschließlich als kompakte Kurzauswahl **dauerhaft in der Seitenleiste**, solange keine Verbindung besteht — die Verbinden-Seite selbst zeigt nur noch das Formular für ein neues, noch unbekanntes Gerät, ohne Dopplung. Ein Klick auf einen Eintrag verbindet direkt (ohne Umweg über das Formular) und öffnet bei Erfolg die Startseite; ein kleines Papierkorb-Symbol entfernt einen Eintrag wieder. Der Name kommt automatisch vom Gerätemodell — eine eigene Umbenennung gibt es bewusst nicht mehr, um die Seitenleiste kompakt zu halten. Sobald eine Verbindung besteht, zeigt dieselbe Stelle stattdessen Gerätename/-modell mit einem „Wechseln"-Button, der die Verbindung trennt und zur Verbinden-Seite zurückführt.
|
||||
|
||||
Bei „Verschlüsselte Verbindung" werden von Windows anerkannte Zertifikate direkt akzeptiert; ein selbstsigniertes Gerätezertifikat (der Normalfall) wird beim ersten Mal mit Fingerabdruck bestätigt und gemerkt, ein später geändertes Zertifikat nie still übernommen (Präfix `tls:` in `known-hosts.json`).
|
||||
|
||||
|
||||
+13
-8
@@ -35,22 +35,27 @@ Typical case: the router boots (LEDs blink) but can no longer be reached, for ex
|
||||
4. Set an IP for access, e.g. `/ip address add address=192.168.88.1/24 interface=ether2`, then reconnect with the app.
|
||||
5. Only if that does not help: factory reset using the reset button on the device.
|
||||
|
||||
## 2. What would you like to do?
|
||||
## 2. Areas
|
||||
|
||||
Right after connecting you choose the area: the setup wizard, "Backup & maintenance" or — only with "Professional network admin" enabled in the settings — the "Expert" area.
|
||||
Once connected, all areas in the sidebar on the left can be clicked freely:
|
||||
|
||||
- Home: model, RouterOS version, serial number and ports (green dot = cable plugged in / link up), plus the RouterOS update (optional, with a warning; afterwards the app reconnects on its own).
|
||||
- Set up: the setup wizard, see chapter 3.
|
||||
- Overview: a diagram of the current configuration. Clicking a box highlights everything connected to it. With "Professional network admin", a box can be changed directly via "Edit".
|
||||
- Devices: see chapter 4.
|
||||
- Backup & maintenance: see chapter 5.
|
||||
- Expert: only with "Professional network admin" enabled in the settings, see chapter 6.
|
||||
|
||||
Help & terms and Settings sit at the bottom of the sidebar and work without a connection too. Clicking an area again reloads it.
|
||||
|
||||
## 3. Setup wizard
|
||||
|
||||
The wizard asks step by step what should be set up. Nothing is changed on the router before you click "Set up now" in the summary.
|
||||
The wizard in the "Set up" area asks what should be set up. The steps at the top can be clicked directly; "Back" and "Next" are at the bottom. The summary only contains what was validly set in visited steps. Nothing is changed on the router before you click "Set up now" in the summary.
|
||||
|
||||
- Device detection: model, RouterOS version, serial number and ports (green dot = cable plugged in / link up).
|
||||
- Existing networks: a diagram of the current configuration. Clicking a box highlights everything connected to it. With "Professional network admin", a box can be changed directly via "Edit".
|
||||
- Devices on the network: see chapter 4.
|
||||
- Internet access, home network, VLANs, Wi-Fi, firewall: the actual setup. The home network is pre-filled with the router's existing network; when applying, existing entries are updated instead of created twice.
|
||||
- If a port that should join the home network is still in use otherwise (its own IP address, DHCP), the wizard offers "Free up port".
|
||||
- "Isolate from home network" separates a VLAN completely: no access to the home network and no router management from the isolated network; only DNS and DHCP stay allowed.
|
||||
- Summary: all changes in plain language, PDF export with credentials and Wi-Fi QR code. "Set up now" first creates a backup, then shows a progress bar and, at the end, what was done.
|
||||
- RouterOS update: optional, with a warning; afterwards the app reconnects on its own.
|
||||
|
||||
## 4. Devices on the network (LAN scanner)
|
||||
|
||||
@@ -85,4 +90,4 @@ Only with "Professional network admin". On the left there are tools and about 50
|
||||
|
||||
## 7. Settings
|
||||
|
||||
Available at the bottom of the sidebar: language, appearance (system, light, dark), update check when connecting, "Professional network admin", test environment, folder and password for backups, show introduction again.
|
||||
At the bottom of the sidebar, changes apply with "Save": language, appearance (system, light, dark), update check when connecting, "Professional network admin", test environment, folder and password for backups, show introduction again.
|
||||
+13
-8
@@ -35,22 +35,27 @@ Typischer Fall: Der Router startet (LEDs blinken), ist aber nicht mehr erreichba
|
||||
4. Für den Zugriff eine IP setzen, z. B. `/ip address add address=192.168.88.1/24 interface=ether2`, dann mit der App neu verbinden.
|
||||
5. Erst wenn das nicht hilft: Werkseinstellungen per Reset-Knopf am Gerät.
|
||||
|
||||
## 2. Was möchtest du tun?
|
||||
## 2. Bereiche
|
||||
|
||||
Direkt nach dem Verbinden wählst du den Bereich: den Einrichtungs-Assistenten, „Backup & Wartung“ oder — nur mit „Professioneller Netzwerker“ in den Einstellungen — den Bereich „Experte“.
|
||||
Nach dem Verbinden sind alle Bereiche links in der Seitenleiste frei anklickbar:
|
||||
|
||||
- Start: Modell, RouterOS-Version, Seriennummer und Anschlüsse (grüner Punkt = Kabel steckt / Verbindung besteht), dazu das RouterOS-Update (optional, mit Warnung; danach verbindet sich die App von selbst wieder).
|
||||
- Einrichten: der Einrichtungs-Assistent, siehe Kapitel 3.
|
||||
- Übersicht: eine Grafik der bestehenden Konfiguration. Ein Klick auf einen Kasten hebt alles hervor, was damit zusammenhängt. Mit „Professioneller Netzwerker“ lässt sich ein Kasten über „Bearbeiten“ direkt ändern.
|
||||
- Geräte: siehe Kapitel 4.
|
||||
- Backup & Wartung: siehe Kapitel 5.
|
||||
- Experte: nur mit „Professioneller Netzwerker“ in den Einstellungen, siehe Kapitel 6.
|
||||
|
||||
Hilfe & Begriffe und Einstellungen stehen unten in der Seitenleiste und gehen auch ohne Verbindung. Ein erneuter Klick auf einen Bereich lädt ihn neu.
|
||||
|
||||
## 3. Einrichtungs-Assistent
|
||||
|
||||
Der Assistent fragt Schritt für Schritt ab, was eingerichtet werden soll. Nichts wird am Router geändert, bevor du in der Zusammenfassung „Jetzt einrichten“ klickst.
|
||||
Der Assistent im Bereich „Einrichten“ fragt ab, was eingerichtet werden soll. Die Schritte oben lassen sich direkt anklicken; „Zurück“ und „Weiter“ stehen unten. Die Zusammenfassung enthält nur, was in besuchten Schritten gültig eingestellt wurde. Nichts wird am Router geändert, bevor du in der Zusammenfassung „Jetzt einrichten“ klickst.
|
||||
|
||||
- Geräte-Erkennung: Modell, RouterOS-Version, Seriennummer und Anschlüsse (grüner Punkt = Kabel steckt / Verbindung besteht).
|
||||
- Vorhandene Netzwerke: eine Grafik der bestehenden Konfiguration. Ein Klick auf einen Kasten hebt alles hervor, was damit zusammenhängt. Mit „Professioneller Netzwerker“ lässt sich ein Kasten über „Bearbeiten“ direkt ändern.
|
||||
- Geräte im Netzwerk: siehe Kapitel 4.
|
||||
- Internet-Zugang, Heimnetzwerk, VLANs, WLAN, Firewall: die eigentliche Einrichtung. Das Heimnetzwerk wird mit dem schon vorhandenen Netz des Routers vorbelegt; beim Anwenden werden vorhandene Einträge aktualisiert statt doppelt angelegt.
|
||||
- Ist ein Anschluss, der ins Heimnetz soll, noch anderweitig belegt (eigene IP-Adresse, DHCP), bietet der Assistent „Port freimachen“ an.
|
||||
- „Von Heimnetz isolieren“ trennt ein VLAN vollständig: kein Zugriff ins Heimnetz und keine Router-Verwaltung aus dem isolierten Netz, nur DNS und DHCP bleiben erlaubt.
|
||||
- Zusammenfassung: alle Änderungen im Klartext, PDF-Export mit Zugangsdaten und WLAN-QR-Code. „Jetzt einrichten“ erstellt zuerst eine Sicherung und zeigt dann einen Fortschrittsbalken und am Ende, was ausgeführt wurde.
|
||||
- RouterOS-Update: optional, mit Warnung; danach verbindet sich die App von selbst wieder.
|
||||
|
||||
## 4. Geräte im Netzwerk (LAN-Scanner)
|
||||
|
||||
@@ -85,4 +90,4 @@ Nur mit „Professioneller Netzwerker“. Links stehen Werkzeuge und rund 50 Rou
|
||||
|
||||
## 7. Einstellungen
|
||||
|
||||
Erreichbar unten in der Seitenleiste: Erscheinungsbild (Wie System, Hell, Dunkel), Update-Prüfung beim Verbinden, „Professioneller Netzwerker“, Testumgebung, Ordner und Passwort für Backups, Einführung erneut zeigen.
|
||||
Unten in der Seitenleiste, Änderungen gelten mit „Speichern“: Sprache, Erscheinungsbild (Wie System, Hell, Dunkel), Update-Prüfung beim Verbinden, „Professioneller Netzwerker“, Testumgebung, Ordner und Passwort für Backups, Einführung erneut zeigen.
|
||||
@@ -5,6 +5,8 @@
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:steps="clr-namespace:MikrotikInstaller.App.ViewModels.Steps"
|
||||
xmlns:stepViews="clr-namespace:MikrotikInstaller.App.Views.Steps"
|
||||
xmlns:vm="clr-namespace:MikrotikInstaller.App.ViewModels"
|
||||
xmlns:views="clr-namespace:MikrotikInstaller.App.Views"
|
||||
xmlns:converters="clr-namespace:MikrotikInstaller.App.Converters"
|
||||
xmlns:viewControls="clr-namespace:MikrotikInstaller.App.Views.Controls"
|
||||
StartupUri="MainWindow.xaml">
|
||||
@@ -32,8 +34,17 @@
|
||||
<DataTemplate DataType="{x:Type steps:ConnectionStepViewModel}">
|
||||
<stepViews:ConnectionStepView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type steps:AreaSelectionStepViewModel}">
|
||||
<stepViews:AreaSelectionStepView />
|
||||
<DataTemplate DataType="{x:Type vm:StartViewModel}">
|
||||
<views:StartView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type vm:SetupWizardViewModel}">
|
||||
<views:SetupWizardView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type vm:HelpViewModel}">
|
||||
<views:HelpView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type vm:SettingsViewModel}">
|
||||
<views:SettingsView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type steps:BackupManagementStepViewModel}">
|
||||
<stepViews:BackupManagementStepView />
|
||||
|
||||
@@ -20,6 +20,42 @@
|
||||
<vm:MainViewModel />
|
||||
</Window.DataContext>
|
||||
|
||||
<Window.Resources>
|
||||
<!-- Ein Bereich der Seitenleiste: RadioButton an MainViewModel.Area gebunden, Tag = Symbol. -->
|
||||
<Style x:Key="NavItem" TargetType="RadioButton">
|
||||
<Setter Property="GroupName" Value="Area" />
|
||||
<Setter Property="Margin" Value="0,0,0,2" />
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="RadioButton">
|
||||
<Border x:Name="Bg" Background="Transparent" CornerRadius="6" Padding="10,8">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ui:SymbolIcon x:Name="Icon" Symbol="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
FontSize="18" Margin="0,0,12,0" VerticalAlignment="Center" />
|
||||
<ContentPresenter VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="Bg" Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter TargetName="Bg" Property="Background" Value="{StaticResource MikrotikAccentSoftBrush}" />
|
||||
<Setter TargetName="Icon" Property="Foreground" Value="{StaticResource MikrotikAccentBrush}" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" Value="0.4" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -38,7 +74,7 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Sidebar: Marke + Schritt-Übersicht -->
|
||||
<!-- Seitenleiste: Marke, Verbindung, Bereiche -->
|
||||
<Border Grid.Column="0" Background="{DynamicResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{DynamicResource DividerStrokeColorDefaultBrush}" BorderThickness="0,0,1,0">
|
||||
<Grid Margin="20,24,16,24">
|
||||
@@ -55,10 +91,10 @@
|
||||
<TextBlock Text="{l:T 'MikroTik Installer'}" FontWeight="SemiBold" FontSize="15" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Verbindungs-Karte: dauerhaft sichtbar, unabhängig vom aktuellen Schritt (Issue #36). -->
|
||||
<!-- Verbindungs-Karte: dauerhaft sichtbar, unabhängig vom aktuellen Bereich (Issue #36). -->
|
||||
<Border Grid.Row="1" Background="{DynamicResource ControlFillColorSecondaryBrush}" CornerRadius="8" Padding="12" Margin="0,0,0,16">
|
||||
<Grid>
|
||||
<StackPanel Visibility="{Binding Connection.IsConnected, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel Visibility="{Binding IsConnected, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,6">
|
||||
<Border Width="8" Height="8" CornerRadius="4" Background="{StaticResource MikrotikAccentBrush}"
|
||||
Margin="0,0,8,0" VerticalAlignment="Center" />
|
||||
@@ -72,7 +108,7 @@
|
||||
Command="{Binding SwitchConnectionCommand}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Visibility="{Binding Connection.IsConnected, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Invert}">
|
||||
<StackPanel Visibility="{Binding IsConnected, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Invert}">
|
||||
<TextBlock Text="{l:T 'Nicht verbunden'}" FontSize="12" Opacity="0.7" Margin="0,0,0,8" />
|
||||
|
||||
<StackPanel Visibility="{Binding Connection.HasSavedRouters, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
@@ -87,7 +123,7 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ui:Button Grid.Column="0" Appearance="Secondary" HorizontalAlignment="Stretch" HorizontalContentAlignment="Left"
|
||||
Command="{Binding DataContext.QuickConnectCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
|
||||
Command="{Binding DataContext.QuickConnectCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
CommandParameter="{Binding}">
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding Name}" FontWeight="SemiBold" FontSize="12" />
|
||||
@@ -95,7 +131,7 @@
|
||||
</StackPanel>
|
||||
</ui:Button>
|
||||
<ui:Button Grid.Column="1" Appearance="Secondary" Margin="4,0,0,0" Padding="6,0" ToolTip="{l:T 'Entfernen'}"
|
||||
Command="{Binding DataContext.RemoveSavedRouterCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
|
||||
Command="{Binding DataContext.Connection.RemoveSavedRouterCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
CommandParameter="{Binding}">
|
||||
<ui:SymbolIcon Symbol="Delete20" />
|
||||
</ui:Button>
|
||||
@@ -106,139 +142,62 @@
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="{l:T 'Neue Verbindung im ersten Schritt einrichten.'}" FontSize="12" Opacity="0.6" TextWrapping="Wrap"
|
||||
<TextBlock Text="{l:T 'Rechts eine neue Verbindung einrichten.'}" FontSize="12" Opacity="0.6" TextWrapping="Wrap"
|
||||
Visibility="{Binding Connection.HasSavedRouters, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Invert}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ScrollViewer, damit bei vielen Schritten (z. B. inkl. übersprungener) auch die
|
||||
unteren Einträge erreichbar bleiben, statt am unteren Fensterrand abgeschnitten
|
||||
zu werden (siehe Issue #35). -->
|
||||
<!-- Bereiche: frei anklickbar, ohne Verbindung gesperrt -->
|
||||
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto" Padding="0,0,4,0">
|
||||
<ItemsControl ItemsSource="{Binding StepNavItems}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Padding="10,8" Margin="0,0,0,2" CornerRadius="6">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource MikrotikAccentSoftBrush}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Border Width="22" Height="22" CornerRadius="11" Margin="0,0,10,0">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="{DynamicResource ControlFillColorSecondaryBrush}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource MikrotikAccentBrush}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsCompleted}" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource MikrotikAccentBrush}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding Number}" FontSize="11" FontWeight="SemiBold"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsCompleted}" Value="True">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<ui:SymbolIcon Symbol="Checkmark24" FontSize="12" Foreground="White"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed">
|
||||
<ui:SymbolIcon.Style>
|
||||
<Style TargetType="ui:SymbolIcon">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsCompleted}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ui:SymbolIcon.Style>
|
||||
</ui:SymbolIcon>
|
||||
</Grid>
|
||||
</Border>
|
||||
<TextBlock Text="{Binding Title}" VerticalAlignment="Center" TextWrapping="Wrap" MaxWidth="150">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<StackPanel IsEnabled="{Binding IsConnected}">
|
||||
<RadioButton Style="{StaticResource NavItem}" Tag="{x:Static ui:SymbolRegular.Home24}" Content="{l:T 'Start'}"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Start}" />
|
||||
<RadioButton Style="{StaticResource NavItem}" Tag="{x:Static ui:SymbolRegular.Wand24}" Content="{l:T 'Einrichten'}"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Setup}" />
|
||||
<RadioButton Style="{StaticResource NavItem}" Tag="{x:Static ui:SymbolRegular.Organization24}" Content="{l:T 'Übersicht'}"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Overview}" />
|
||||
<RadioButton Style="{StaticResource NavItem}" Tag="{x:Static ui:SymbolRegular.Desktop24}" Content="{l:T 'Geräte'}"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Devices}" />
|
||||
<RadioButton Style="{StaticResource NavItem}" Tag="{x:Static ui:SymbolRegular.ArrowSync24}" Content="{l:T 'Backup & Wartung'}"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Backup}" />
|
||||
<RadioButton Style="{StaticResource NavItem}" Tag="{x:Static ui:SymbolRegular.WrenchScrewdriver24}" Content="{l:T 'Experte'}"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Expert}"
|
||||
Visibility="{Binding ShowExpert, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<StackPanel Grid.Row="3" Margin="0,12,0,0">
|
||||
<ui:Button Content="{l:T 'Hilfe & Begriffe'}" Appearance="Transparent" HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left" Click="OnOpenHelp">
|
||||
<ui:Button.Icon>
|
||||
<ui:SymbolIcon Symbol="BookQuestionMark24" />
|
||||
</ui:Button.Icon>
|
||||
</ui:Button>
|
||||
<ui:Button Content="{l:T 'Einstellungen'}" Appearance="Transparent" HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left" Click="OnOpenSettings">
|
||||
<ui:Button.Icon>
|
||||
<ui:SymbolIcon Symbol="Settings24" />
|
||||
</ui:Button.Icon>
|
||||
</ui:Button>
|
||||
<RadioButton Style="{StaticResource NavItem}" Tag="{x:Static ui:SymbolRegular.BookQuestionMark24}" Content="{l:T 'Hilfe & Begriffe'}"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Help}" />
|
||||
<RadioButton Style="{StaticResource NavItem}" Tag="{x:Static ui:SymbolRegular.Settings24}" Content="{l:T 'Einstellungen'}"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Settings}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Inhalt: aktueller Schritt -->
|
||||
<!-- Inhalt: aktueller Bereich -->
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="{Binding CurrentStep.Title}" FontSize="26" FontWeight="SemiBold" Margin="36,28,36,0" />
|
||||
<TextBlock Grid.Row="0" Text="{Binding PageTitle}" FontSize="26" FontWeight="SemiBold" Margin="36,28,36,0" />
|
||||
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" Padding="36,0,28,16">
|
||||
<ContentControl Content="{Binding CurrentStep}" Margin="0,4,0,0" />
|
||||
<ScrollViewer Grid.Row="1" Padding="36,0,28,16">
|
||||
<ScrollViewer.Style>
|
||||
<Style TargetType="ScrollViewer" BasedOn="{StaticResource {x:Type ScrollViewer}}">
|
||||
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding PageScrolls}" Value="False">
|
||||
<Setter Property="VerticalScrollBarVisibility" Value="Disabled" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ScrollViewer.Style>
|
||||
<ContentControl Content="{Binding CurrentPage}" Margin="0,4,0,0" />
|
||||
</ScrollViewer>
|
||||
|
||||
<Border Grid.Row="2" BorderBrush="{DynamicResource DividerStrokeColorDefaultBrush}" BorderThickness="0,1,0,0">
|
||||
<Grid Margin="36,16,36,20">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ui:Button Grid.Column="1" Content="{l:T 'Zurück'}" Command="{Binding GoBackCommand}" Margin="0,0,8,0" />
|
||||
<ui:Button Grid.Column="2" Content="{l:T 'Weiter'}" Appearance="Primary" Command="{Binding GoNextCommand}"
|
||||
Visibility="{Binding IsLastStep, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Invert}" />
|
||||
<ui:Button Grid.Column="2" Content="{l:T 'Beenden'}" Appearance="Primary" Command="{Binding FinishCommand}"
|
||||
Visibility="{Binding IsLastStep, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -11,11 +11,6 @@ public partial class MainWindow : FluentWindow
|
||||
InitializeComponent();
|
||||
Closing += OnClosing;
|
||||
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
{
|
||||
viewModel.CloseRequested += (_, _) => Close();
|
||||
}
|
||||
|
||||
// Folgt Hell/Dunkel-Wechseln des Windows-Systemthemes zur Laufzeit — nur bei "Wie System";
|
||||
// updateAccents:false, damit unser MikroTik-Grün-Akzent dabei erhalten bleibt.
|
||||
WatchSystemThemeIfWanted();
|
||||
@@ -55,13 +50,6 @@ public partial class MainWindow : FluentWindow
|
||||
_isWatchingSystemTheme = wanted;
|
||||
}
|
||||
|
||||
/// <summary>Nicht modal, damit man beim Lesen weiterarbeiten kann.</summary>
|
||||
private void OnOpenHelp(object sender, System.Windows.RoutedEventArgs e) =>
|
||||
new Views.HelpWindow { Owner = this }.Show();
|
||||
|
||||
private void OnOpenSettings(object sender, System.Windows.RoutedEventArgs e) =>
|
||||
new Views.SettingsWindow { Owner = this }.ShowDialog();
|
||||
|
||||
private async void OnClosing(object? sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
namespace MikrotikInstaller.App.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Der grundsätzliche Bereich, den der Nutzer direkt nach dem Verbinden wählt — bestimmt, welche
|
||||
/// Schritte im weiteren Verlauf übersprungen werden (siehe <see cref="Steps.WizardStepViewModelBase.ShouldSkip"/>
|
||||
/// der jeweiligen Schritte).
|
||||
/// </summary>
|
||||
/// <summary>Frei anklickbare Bereiche der Seitenleiste (Bereichs-Navigation wie in der Mac-Version).</summary>
|
||||
public enum AppArea
|
||||
{
|
||||
/// <summary>Der komplette Einrichtungs-Assistent (Internet-Zugang, Heimnetzwerk, VLANs, WLAN, Firewall, Zusammenfassung).</summary>
|
||||
SetupWizard,
|
||||
Start,
|
||||
Setup,
|
||||
Overview,
|
||||
Devices,
|
||||
Backup,
|
||||
|
||||
/// <summary>Direkter Zugriff auf Backups (auflisten, erstellen, wiederherstellen) ohne den restlichen Assistenten.</summary>
|
||||
BackupManagement,
|
||||
|
||||
/// <summary>Generischer Zugriff auf RouterOS-Menüs plus Werkzeuge (Issue #21), nur mit „Professioneller Netzwerker“.</summary>
|
||||
/// <summary>Nur mit „Professioneller Netzwerker“ sichtbar (Mac v1.3.0).</summary>
|
||||
Expert,
|
||||
|
||||
/// <summary>Hilfe und Einstellungen gehen auch ohne Verbindung.</summary>
|
||||
Help,
|
||||
Settings,
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using MikrotikInstaller.Core.Localization;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
@@ -10,59 +10,165 @@ using MikrotikInstaller.Core.Connectivity;
|
||||
namespace MikrotikInstaller.App.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Steuert die Schritt-für-Schritt-Navigation des Einrichtungs-Assistenten.
|
||||
/// Bereichs-Navigation: Seitenleiste mit frei anklickbaren Bereichen. Ohne Verbindung zeigt der Inhalt
|
||||
/// die Verbinden-Seite; nur Hilfe und Einstellungen gehen dann trotzdem.
|
||||
/// </summary>
|
||||
public partial class MainViewModel : ObservableObject
|
||||
{
|
||||
private readonly WizardSession _session = new();
|
||||
private readonly DispatcherTimer _heartbeat = new() { Interval = TimeSpan.FromSeconds(30) };
|
||||
private readonly HelpViewModel _help = new();
|
||||
private SettingsViewModel? _settings;
|
||||
private Pages? _pages;
|
||||
|
||||
/// <summary>Je Verbindung neu angelegt, damit nichts vom vorherigen Gerät hängen bleibt.</summary>
|
||||
private sealed record Pages(
|
||||
StartViewModel Start,
|
||||
SetupWizardViewModel Setup,
|
||||
NetworkAnalysisStepViewModel Overview,
|
||||
LanScanStepViewModel Devices,
|
||||
BackupManagementStepViewModel Backup,
|
||||
ExpertStepViewModel Expert);
|
||||
|
||||
public MainViewModel()
|
||||
{
|
||||
Steps =
|
||||
[
|
||||
new ConnectionStepViewModel(_session),
|
||||
new AreaSelectionStepViewModel(_session),
|
||||
new BackupManagementStepViewModel(_session),
|
||||
new ExpertStepViewModel(_session),
|
||||
new DeviceOverviewStepViewModel(_session),
|
||||
new NetworkAnalysisStepViewModel(_session),
|
||||
new LanScanStepViewModel(_session),
|
||||
new ModeSelectionStepViewModel(_session),
|
||||
new WanStepViewModel(_session),
|
||||
new LanStepViewModel(_session),
|
||||
new VlanStepViewModel(_session),
|
||||
new WlanStepViewModel(_session),
|
||||
new FirewallStepViewModel(_session),
|
||||
new SummaryStepViewModel(_session),
|
||||
new UpdateStepViewModel(_session),
|
||||
];
|
||||
|
||||
foreach (var step in Steps)
|
||||
{
|
||||
step.PropertyChanged += (_, _) =>
|
||||
{
|
||||
GoNextCommand.NotifyCanExecuteChanged();
|
||||
// Grob, aber einfach: jede Step-Änderung kann bedeuten, dass sich _session.Device
|
||||
// (gesetzt von DeviceOverview- oder BackupManagementStepViewModel) inzwischen gefüllt
|
||||
// hat — die Sidebar zeigt das dauerhaft an, unabhängig vom aktuellen Schritt.
|
||||
OnPropertyChanged(nameof(ConnectedDeviceLabel));
|
||||
};
|
||||
}
|
||||
|
||||
CurrentStepIndex = 0;
|
||||
Connection = new ConnectionStepViewModel(_session);
|
||||
Connection.PropertyChanged += OnConnectionChanged;
|
||||
_ = Connection.OnActivatedAsync();
|
||||
|
||||
_session.ConnectionEnded += (_, _) =>
|
||||
{
|
||||
Connection.IsConnected = false;
|
||||
OnPropertyChanged(nameof(ConnectedDeviceLabel));
|
||||
};
|
||||
UserSettings.Changed += (_, _) =>
|
||||
{
|
||||
OnPropertyChanged(nameof(ShowExpert));
|
||||
if (Area == AppArea.Expert && !ShowExpert)
|
||||
{
|
||||
Area = AppArea.Start;
|
||||
}
|
||||
};
|
||||
_heartbeat.Tick += async (_, _) => await CheckConnectionAsync();
|
||||
_heartbeat.Start();
|
||||
}
|
||||
|
||||
public ConnectionState ConnectionState => _session.State;
|
||||
|
||||
public ConnectionStepViewModel Connection { get; }
|
||||
|
||||
public bool IsConnected => Connection.IsConnected && _pages is not null;
|
||||
|
||||
public bool ShowExpert => UserSettings.Current.ProfessionalMode;
|
||||
|
||||
/// <summary>Geräte-Modell, sobald bekannt, sonst nur der Host.</summary>
|
||||
public string? ConnectedDeviceLabel => _session.Device is { } device ? $"{device.IdentityName} ({device.BoardModel})" : Connection.Host;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(CurrentPage))]
|
||||
[NotifyPropertyChangedFor(nameof(PageTitle))]
|
||||
[NotifyPropertyChangedFor(nameof(PageScrolls))]
|
||||
private AppArea _area = AppArea.Start;
|
||||
|
||||
public object CurrentPage => Area switch
|
||||
{
|
||||
AppArea.Help => _help,
|
||||
AppArea.Settings => _settings ??= new SettingsViewModel(),
|
||||
_ when _pages is null => Connection,
|
||||
AppArea.Setup => _pages.Setup,
|
||||
AppArea.Overview => _pages.Overview,
|
||||
AppArea.Devices => _pages.Devices,
|
||||
AppArea.Backup => _pages.Backup,
|
||||
AppArea.Expert => _pages.Expert,
|
||||
_ => _pages.Start,
|
||||
};
|
||||
|
||||
/// <summary>„Einrichten“ hat eine eigene Scroll-Fläche, damit Schrittleiste und Zurück/Weiter stehen bleiben.</summary>
|
||||
public bool PageScrolls => CurrentPage is not SetupWizardViewModel;
|
||||
|
||||
public string PageTitle => Area switch
|
||||
{
|
||||
AppArea.Help => L.T("Hilfe & Begriffe"),
|
||||
AppArea.Settings => L.T("Einstellungen"),
|
||||
_ when _pages is null => L.T("Verbinden"),
|
||||
AppArea.Setup => L.T("Einrichten"),
|
||||
AppArea.Overview => L.T("Übersicht"),
|
||||
AppArea.Backup => L.T("Backup & Wartung"),
|
||||
AppArea.Expert => L.T("Experte"),
|
||||
_ => ((WizardStepViewModelBase)CurrentPage).Title,
|
||||
};
|
||||
|
||||
partial void OnAreaChanged(AppArea oldValue, AppArea newValue)
|
||||
{
|
||||
if (oldValue == AppArea.Settings)
|
||||
{
|
||||
_settings = null; // beim nächsten Öffnen frisch aus den gespeicherten Werten
|
||||
}
|
||||
|
||||
if (CurrentPage is WizardStepViewModelBase page)
|
||||
{
|
||||
_ = page.OnActivatedAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void Navigate(AppArea area)
|
||||
{
|
||||
if (area == Area)
|
||||
{
|
||||
OnAreaChanged(area, area); // erneuter Klick lädt den Bereich neu
|
||||
}
|
||||
|
||||
Area = area;
|
||||
}
|
||||
|
||||
private void OnConnectionChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName != nameof(ConnectionStepViewModel.IsConnected))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Connection.IsConnected)
|
||||
{
|
||||
_ = OnConnectedAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
_pages = null;
|
||||
RefreshShell();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnConnectedAsync()
|
||||
{
|
||||
_session.ResetPlan();
|
||||
var device = new DeviceOverviewStepViewModel(_session);
|
||||
device.PropertyChanged += (_, _) => OnPropertyChanged(nameof(ConnectedDeviceLabel));
|
||||
|
||||
// Liest Modell und Schnittstellen aus und trägt den Router in „Bekannte Router“ ein.
|
||||
await device.OnActivatedAsync();
|
||||
_pages = new Pages(
|
||||
new StartViewModel(device, new UpdateStepViewModel(_session)),
|
||||
new SetupWizardViewModel(_session),
|
||||
new NetworkAnalysisStepViewModel(_session),
|
||||
new LanScanStepViewModel(_session),
|
||||
new BackupManagementStepViewModel(_session),
|
||||
new ExpertStepViewModel(_session));
|
||||
|
||||
RefreshShell();
|
||||
Navigate(AppArea.Start);
|
||||
}
|
||||
|
||||
private void RefreshShell()
|
||||
{
|
||||
OnPropertyChanged(nameof(IsConnected));
|
||||
OnPropertyChanged(nameof(ConnectedDeviceLabel));
|
||||
OnPropertyChanged(nameof(CurrentPage));
|
||||
OnPropertyChanged(nameof(PageTitle));
|
||||
OnPropertyChanged(nameof(PageScrolls));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Herzschlag alle 30 s, nur bei aktivem Fenster und ohne laufende längere Aktion (geringe Router-Last,
|
||||
/// Mac v1.3.0): fällt die Verbindung weg, wird automatisch neu verbunden.
|
||||
@@ -89,97 +195,21 @@ public partial class MainViewModel : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<WizardStepViewModelBase> Steps { get; }
|
||||
|
||||
/// <summary>Für die dauerhafte Verbindungs-Anzeige in der Sidebar — immer derselbe erste Schritt.</summary>
|
||||
public ConnectionStepViewModel Connection => (ConnectionStepViewModel)Steps[0];
|
||||
|
||||
/// <summary>Geräte-Modell, sobald bekannt (nach Geräte-Erkennung oder Backup-Verwaltung), sonst nur der Host.</summary>
|
||||
public string? ConnectedDeviceLabel => _session.Device is { } device ? $"{device.IdentityName} ({device.BoardModel})" : Connection.Host;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(CurrentStep))]
|
||||
[NotifyPropertyChangedFor(nameof(ProgressText))]
|
||||
[NotifyPropertyChangedFor(nameof(IsFirstStep))]
|
||||
[NotifyPropertyChangedFor(nameof(IsLastStep))]
|
||||
[NotifyPropertyChangedFor(nameof(StepNavItems))]
|
||||
[NotifyCanExecuteChangedFor(nameof(GoBackCommand))]
|
||||
[NotifyCanExecuteChangedFor(nameof(GoNextCommand))]
|
||||
private int _currentStepIndex;
|
||||
|
||||
public WizardStepViewModelBase CurrentStep => Steps[CurrentStepIndex];
|
||||
|
||||
public string ProgressText => L.F("Schritt {0} von {1}", CurrentStepIndex + 1, Steps.Count);
|
||||
|
||||
public IReadOnlyList<StepNavItem> StepNavItems => Steps
|
||||
.Select((step, index) => new StepNavItem(index + 1, step.Title, index == CurrentStepIndex, index < CurrentStepIndex))
|
||||
.ToList();
|
||||
|
||||
public bool IsFirstStep => CurrentStepIndex == 0;
|
||||
|
||||
public bool IsLastStep => CurrentStepIndex == Steps.Count - 1;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanGoBack))]
|
||||
private async Task GoBackAsync()
|
||||
{
|
||||
do
|
||||
{
|
||||
CurrentStepIndex--;
|
||||
}
|
||||
while (CurrentStepIndex > 0 && CurrentStep.ShouldSkip);
|
||||
|
||||
await CurrentStep.OnActivatedAsync();
|
||||
}
|
||||
|
||||
private bool CanGoBack() => !IsFirstStep;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanGoNext))]
|
||||
private async Task GoNextAsync()
|
||||
{
|
||||
do
|
||||
{
|
||||
CurrentStepIndex++;
|
||||
}
|
||||
while (CurrentStepIndex < Steps.Count - 1 && CurrentStep.ShouldSkip);
|
||||
|
||||
await CurrentStep.OnActivatedAsync();
|
||||
}
|
||||
|
||||
private bool CanGoNext() => !IsLastStep && CurrentStep.CanGoNext;
|
||||
|
||||
/// <summary>
|
||||
/// Verbindet über einen Sidebar-Klick auf einen bekannten Router direkt (ohne Umweg über die
|
||||
/// Formularfelder des Verbindungs-Schritts) und geht bei Erfolg automatisch weiter — nur relevant,
|
||||
/// solange noch keine Verbindung besteht, denn nur dann zeigt die Sidebar diese Kurzauswahl.
|
||||
/// </summary>
|
||||
/// <summary>Ein-Klick-Verbinden aus der Seitenleiste; die Navigation zur Startseite übernimmt <see cref="OnConnectionChanged"/>.</summary>
|
||||
[RelayCommand]
|
||||
private async Task QuickConnectAsync(SavedRouterEntry entry)
|
||||
{
|
||||
await Connection.ConnectToSavedRouterCommand.ExecuteAsync(entry);
|
||||
if (Connection.IsConnected)
|
||||
{
|
||||
await GoNextCommand.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
private Task QuickConnectAsync(SavedRouterEntry entry) => Connection.ConnectToSavedRouterCommand.ExecuteAsync(entry);
|
||||
|
||||
/// <summary>Trennt die aktuelle Verbindung und springt zurück zum Verbindungs-Schritt, um ein anderes Gerät zu wählen.</summary>
|
||||
/// <summary>Trennt die aktuelle Verbindung und zeigt wieder die Verbinden-Seite.</summary>
|
||||
[RelayCommand]
|
||||
private async Task SwitchConnectionAsync()
|
||||
{
|
||||
await _session.DisposeClientAsync();
|
||||
_session.Device = null;
|
||||
Connection.IsConnected = false;
|
||||
|
||||
CurrentStepIndex = 0;
|
||||
await CurrentStep.OnActivatedAsync();
|
||||
await Connection.OnActivatedAsync();
|
||||
Area = AppArea.Start;
|
||||
}
|
||||
|
||||
/// <summary>Wird ausgelöst, wenn der Nutzer auf dem letzten Schritt „Beenden" klickt.</summary>
|
||||
public event EventHandler? CloseRequested;
|
||||
|
||||
[RelayCommand]
|
||||
private void Finish() => CloseRequested?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
/// <summary>Wird beim Schließen des Hauptfensters aufgerufen, um die Geräteverbindung sauber zu beenden.</summary>
|
||||
public Task DisposeSessionAsync() => _session.DisposeClientAsync();
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using MikrotikInstaller.Core.Settings;
|
||||
|
||||
namespace MikrotikInstaller.App.ViewModels;
|
||||
|
||||
/// <summary>Einstellungen-Fenster (Mac: Einstellungen → Allgemein/Darstellung). Änderungen gelten erst mit „Speichern".</summary>
|
||||
/// <summary>Bereich „Einstellungen“ (Mac: Einstellungen → Allgemein/Darstellung). Änderungen gelten erst mit „Speichern".</summary>
|
||||
public partial class SettingsViewModel : ObservableObject
|
||||
{
|
||||
public SettingsViewModel()
|
||||
@@ -58,8 +58,8 @@ public partial class SettingsViewModel : ObservableObject
|
||||
[ObservableProperty]
|
||||
private string? _errorMessage;
|
||||
|
||||
/// <summary>Wird nach erfolgreichem Speichern ausgelöst, damit das Fenster sich schließt.</summary>
|
||||
public event EventHandler? Saved;
|
||||
[ObservableProperty]
|
||||
private string? _statusMessage;
|
||||
|
||||
[RelayCommand]
|
||||
private void ChooseBackupFolder()
|
||||
@@ -75,6 +75,7 @@ public partial class SettingsViewModel : ObservableObject
|
||||
private void Save()
|
||||
{
|
||||
ErrorMessage = null;
|
||||
StatusMessage = null;
|
||||
if (RemoveBackupPassword)
|
||||
{
|
||||
UserSettings.SetBackupPassword(null);
|
||||
@@ -97,7 +98,10 @@ public partial class SettingsViewModel : ObservableObject
|
||||
BackupFolder = BackupFolder == new AppSettings().EffectiveBackupFolder ? null : BackupFolder,
|
||||
IntroCompleted = current.IntroCompleted && !RestartIntro,
|
||||
});
|
||||
Saved?.Invoke(this, EventArgs.Empty);
|
||||
StatusMessage = L.T("Gespeichert.");
|
||||
HasBackupPassword = UserSettings.BackupPassword is not null;
|
||||
NewBackupPassword = string.Empty;
|
||||
RemoveBackupPassword = false;
|
||||
|
||||
// Die Oberfläche wird beim Laden übersetzt — eine neue Sprache gilt nach einem Neustart vollständig.
|
||||
if (languageChanged && System.Windows.MessageBox.Show(
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using MikrotikInstaller.App.ViewModels.Steps;
|
||||
using MikrotikInstaller.Core.Localization;
|
||||
|
||||
namespace MikrotikInstaller.App.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Bereich „Einrichten“: der Assistent mit frei anklickbaren Schritten und eigener Zurück/Weiter-Leiste.
|
||||
/// Die Zusammenfassung wendet nur an, was in besuchten Schritten gültig eingestellt wurde.
|
||||
/// </summary>
|
||||
public partial class SetupWizardViewModel : WizardStepViewModelBase
|
||||
{
|
||||
private readonly IReadOnlyList<WizardStepViewModelBase> _allSteps;
|
||||
private readonly HashSet<WizardStepViewModelBase> _visited = [];
|
||||
|
||||
public SetupWizardViewModel(WizardSession session)
|
||||
: base(L.T("Einrichten"), string.Empty)
|
||||
{
|
||||
_allSteps =
|
||||
[
|
||||
new ModeSelectionStepViewModel(session),
|
||||
new WanStepViewModel(session),
|
||||
new LanStepViewModel(session),
|
||||
new VlanStepViewModel(session),
|
||||
new WlanStepViewModel(session),
|
||||
new FirewallStepViewModel(session),
|
||||
new SummaryStepViewModel(session),
|
||||
];
|
||||
_currentStep = _allSteps[0];
|
||||
|
||||
foreach (var step in _allSteps)
|
||||
{
|
||||
step.PropertyChanged += (_, _) => GoNextCommand.NotifyCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Ohne „Professioneller Netzwerker“ entfällt die Moduswahl, ohne WLAN-Schnittstelle der WLAN-Schritt.</summary>
|
||||
public IReadOnlyList<WizardStepViewModelBase> Steps => _allSteps.Where(s => !s.ShouldSkip).ToList();
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(StepNavItems))]
|
||||
[NotifyPropertyChangedFor(nameof(IsLastStep))]
|
||||
[NotifyCanExecuteChangedFor(nameof(GoBackCommand))]
|
||||
[NotifyCanExecuteChangedFor(nameof(GoNextCommand))]
|
||||
private WizardStepViewModelBase _currentStep;
|
||||
|
||||
private int CurrentIndex => Steps.ToList().IndexOf(CurrentStep);
|
||||
|
||||
public IReadOnlyList<StepNavItem> StepNavItems => Steps
|
||||
.Select((step, index) => new StepNavItem(index + 1, step.Title, step == CurrentStep, step != CurrentStep && _visited.Contains(step)))
|
||||
.ToList();
|
||||
|
||||
public bool IsLastStep => CurrentIndex == Steps.Count - 1;
|
||||
|
||||
public override Task OnActivatedAsync()
|
||||
{
|
||||
// Wird ein Schritt zwischendurch unsichtbar (z. B. Moduswahl nach Abwahl von „Professioneller Netzwerker“), zurück zum ersten.
|
||||
return GoToAsync(CurrentIndex < 0 ? Steps[0] : CurrentStep);
|
||||
}
|
||||
|
||||
private async Task GoToAsync(WizardStepViewModelBase step)
|
||||
{
|
||||
CurrentStep = step;
|
||||
_visited.Add(step);
|
||||
OnPropertyChanged(nameof(StepNavItems));
|
||||
await step.OnActivatedAsync();
|
||||
}
|
||||
|
||||
/// <summary>Klick auf einen Schritt in der Leiste (Nummer ab 1).</summary>
|
||||
[RelayCommand]
|
||||
private Task GoToStepAsync(int number) => GoToAsync(Steps[number - 1]);
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanGoBack))]
|
||||
private Task GoBackAsync() => GoToAsync(Steps[CurrentIndex - 1]);
|
||||
|
||||
private bool CanGoBack() => CurrentIndex > 0;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanGoNextStep))]
|
||||
private Task GoNextAsync() => GoToAsync(Steps[CurrentIndex + 1]);
|
||||
|
||||
private bool CanGoNextStep() => !IsLastStep && CurrentStep.CanGoNext;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using MikrotikInstaller.App.ViewModels.Steps;
|
||||
using MikrotikInstaller.Core.Localization;
|
||||
|
||||
namespace MikrotikInstaller.App.ViewModels;
|
||||
|
||||
/// <summary>Startseite nach dem Verbinden: Schnellzugriffe, Gerätedaten und RouterOS-Update.</summary>
|
||||
public sealed class StartViewModel(DeviceOverviewStepViewModel device, UpdateStepViewModel update)
|
||||
: WizardStepViewModelBase(L.T("Start"), L.T("Dein Gerät auf einen Blick. Wähle links oder hier unten, was du tun möchtest."))
|
||||
{
|
||||
public DeviceOverviewStepViewModel Device { get; } = device;
|
||||
|
||||
public UpdateStepViewModel Update { get; } = update;
|
||||
|
||||
/// <summary>Das Gerät wird schon beim Verbinden ausgelesen, hier nur der Update-Stand aufgefrischt.</summary>
|
||||
public override Task OnActivatedAsync() => Update.OnActivatedAsync();
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using MikrotikInstaller.Core.Localization;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace MikrotikInstaller.App.ViewModels.Steps;
|
||||
|
||||
/// <summary>
|
||||
/// Zweiter Schritt, direkt nach der Verbindung: Wahl zwischen dem kompletten Einrichtungs-Assistenten
|
||||
/// und der eigenständigen Backup-Verwaltung (auflisten, erstellen, wiederherstellen — ohne den Rest
|
||||
/// des Interviews). Die Wahl steuert <see cref="WizardSession.SelectedArea"/> und damit, welche der
|
||||
/// folgenden Schritte per <see cref="WizardStepViewModelBase.ShouldSkip"/> übersprungen werden.
|
||||
/// Der Einrichtungs-Assistent ist vorausgewählt.
|
||||
/// </summary>
|
||||
public partial class AreaSelectionStepViewModel : WizardStepViewModelBase
|
||||
{
|
||||
private readonly WizardSession _session;
|
||||
|
||||
public AreaSelectionStepViewModel(WizardSession session)
|
||||
: base(
|
||||
title: L.T("Was möchtest du tun?"),
|
||||
description: L.T("Wähle, ob du dein Gerät komplett neu einrichten oder Backups und Wartung erledigen möchtest."))
|
||||
{
|
||||
_session = session;
|
||||
_area = session.SelectedArea;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private AppArea _area;
|
||||
|
||||
/// <summary>Der Experte-Bereich ist nur mit „Professioneller Netzwerker“ sichtbar (Mac v1.3.0).</summary>
|
||||
public bool ShowExpert => UserSettings.Current.ProfessionalMode;
|
||||
|
||||
public override Task OnActivatedAsync()
|
||||
{
|
||||
if (_session.SelectedArea == AppArea.Expert && !ShowExpert)
|
||||
{
|
||||
_session.SelectedArea = AppArea.SetupWizard;
|
||||
}
|
||||
|
||||
Area = _session.SelectedArea;
|
||||
OnPropertyChanged(nameof(ShowExpert));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
partial void OnAreaChanged(AppArea value) => _session.SelectedArea = value;
|
||||
}
|
||||
@@ -12,11 +12,9 @@ using MikrotikInstaller.Core.Maintenance;
|
||||
namespace MikrotikInstaller.App.ViewModels.Steps;
|
||||
|
||||
/// <summary>
|
||||
/// Eigenständiger Bereich für alles rund um Backups (auflisten, erstellen, wiederherstellen), erreichbar
|
||||
/// direkt nach der Verbindung über <see cref="AreaSelectionStepViewModel"/> — ohne den restlichen
|
||||
/// Einrichtungs-Assistenten zu durchlaufen. Liest das Gerät (Modell, Architektur, Seriennummer) dafür
|
||||
/// selbst aus, unabhängig von <see cref="DeviceOverviewStepViewModel"/>, die in diesem Bereich
|
||||
/// übersprungen wird. Rein informativ bis auf die Backup-Aktionen selbst — verändert sonst nichts am
|
||||
/// Eigenständiger Bereich „Backup & Wartung“ (auflisten, erstellen, wiederherstellen, Neustart, Firmware,
|
||||
/// Werksreset). Liest das Gerät (Modell, Architektur, Seriennummer) beim Öffnen selbst neu aus, damit
|
||||
/// die Angaben nach Neustart oder Restore stimmen. Rein informativ bis auf die Backup-Aktionen selbst — verändert sonst nichts am
|
||||
/// Gerät und ist nicht Teil der vom Assistenten geplanten Soll-Konfiguration.
|
||||
/// </summary>
|
||||
public partial class BackupManagementStepViewModel : WizardStepViewModelBase
|
||||
@@ -33,7 +31,6 @@ public partial class BackupManagementStepViewModel : WizardStepViewModelBase
|
||||
|
||||
public ObservableCollection<BackupSelectionItemViewModel> AvailableBackups { get; } = [];
|
||||
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.BackupManagement;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoadingDevice;
|
||||
|
||||
@@ -42,8 +42,6 @@ public partial class DeviceOverviewStepViewModel : WizardStepViewModelBase
|
||||
|
||||
public override bool CanGoNext => Device is not null;
|
||||
|
||||
/// <summary>Bei "Backup verwalten" liest die eigenständige Backup-Sektion das Gerät selbst aus, ohne diesen Schritt.</summary>
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.SetupWizard;
|
||||
|
||||
private readonly List<DateTimeOffset> _serialClicks = [];
|
||||
|
||||
|
||||
@@ -109,7 +109,6 @@ public partial class ExpertStepViewModel : WizardStepViewModelBase
|
||||
Tools = new ExpertTools(session);
|
||||
}
|
||||
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.Expert;
|
||||
|
||||
public IReadOnlyList<ExpertMenuItem> Menus { get; }
|
||||
|
||||
|
||||
@@ -37,8 +37,6 @@ public partial class FirewallStepViewModel : WizardStepViewModelBase
|
||||
|
||||
public override bool CanGoNext => PortForwards.All(IsValid) && BlockedAddressesValidationMessage is null;
|
||||
|
||||
/// <summary>Bei "Backup wiederherstellen" wird direkt zur Zusammenfassung gesprungen, ohne die Konfigurations-Schritte.</summary>
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.SetupWizard;
|
||||
|
||||
public override Task OnActivatedAsync()
|
||||
{
|
||||
|
||||
@@ -45,8 +45,6 @@ public partial class LanScanStepViewModel : WizardStepViewModelBase
|
||||
|
||||
public override bool CanGoNext => !IsLoading;
|
||||
|
||||
/// <summary>Bei "Backup verwalten" nicht relevant — die eigenständige Backup-Sektion braucht keinen LAN-Scan.</summary>
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.SetupWizard;
|
||||
|
||||
public bool ShowEmptyHint => !IsLoading && ErrorMessage is null && !HasDevices;
|
||||
|
||||
|
||||
@@ -82,8 +82,6 @@ public partial class LanStepViewModel : WizardStepViewModelBase
|
||||
|
||||
public override bool CanGoNext => ValidationMessage is null;
|
||||
|
||||
/// <summary>Bei "Backup wiederherstellen" wird direkt zur Zusammenfassung gesprungen, ohne die Konfigurations-Schritte.</summary>
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.SetupWizard;
|
||||
|
||||
public override async Task OnActivatedAsync()
|
||||
{
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace MikrotikInstaller.App.ViewModels.Steps;
|
||||
/// <summary>
|
||||
/// Wahl zwischen dem geführten Assistenten (Standard, für die meisten Nutzer passend) und dem
|
||||
/// Experten-Modus, der in den folgenden Schritten zusätzliche, technischere RouterOS-Optionen einblendet.
|
||||
/// Die Wahl blockiert nie das Weitergehen — der geführte Assistent ist vorausgewählt. Bei
|
||||
/// "Backup verwalten" (<see cref="AppArea.BackupManagement"/>) nicht relevant und übersprungen.
|
||||
/// Die Wahl blockiert nie das Weitergehen — der geführte Assistent ist vorausgewählt. Nur mit
|
||||
/// „Professioneller Netzwerker“ sichtbar.
|
||||
/// </summary>
|
||||
public partial class ModeSelectionStepViewModel : WizardStepViewModelBase
|
||||
{
|
||||
@@ -26,7 +26,7 @@ public partial class ModeSelectionStepViewModel : WizardStepViewModelBase
|
||||
private bool _isExpertMode;
|
||||
|
||||
/// <summary>Ohne „Professioneller Netzwerker" gibt es nichts zu wählen — dann immer der geführte Assistent.</summary>
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.SetupWizard || !UserSettings.Current.ProfessionalMode;
|
||||
public override bool ShouldSkip => !UserSettings.Current.ProfessionalMode;
|
||||
|
||||
public override Task OnActivatedAsync()
|
||||
{
|
||||
|
||||
@@ -12,14 +12,10 @@ using MikrotikInstaller.Core.Expert;
|
||||
namespace MikrotikInstaller.App.ViewModels.Steps;
|
||||
|
||||
/// <summary>
|
||||
/// Dritter Schritt: liest aus, welche Netzwerke auf einem Bestandsgerät bereits eingerichtet sind, und
|
||||
/// stellt sie als anklickbare, nach Kategorien gruppierte Grafik dar. Rein informativ — verändert
|
||||
/// nichts am Gerät. Kann nicht anhand des eigenen (erst nach dem Auslesen feststehenden) Ergebnisses
|
||||
/// per <see cref="ShouldSkip"/> übersprungen werden: die Wizard-Navigation prüft <c>ShouldSkip</c>,
|
||||
/// bevor <see cref="OnActivatedAsync"/> für den Ziel-Schritt läuft (siehe <c>MainViewModel.GoNextAsync</c>)
|
||||
/// — zum Zeitpunkt der Prüfung wäre das Ergebnis der Analyse also noch gar nicht bekannt. Stattdessen
|
||||
/// zeigt die View bei leerem Ergebnis einen kurzen Hinweistext statt einer leeren Grafik. Übersprungen
|
||||
/// wird dieser Schritt nur aus einem vorher schon feststehenden Grund: dem gewählten <see cref="AppArea"/>.
|
||||
/// Bereich „Übersicht“: liest aus, welche Netzwerke auf dem Gerät bereits eingerichtet sind, und
|
||||
/// stellt sie als anklickbare, nach Kategorien gruppierte Grafik dar. Verändert nichts am Gerät, außer
|
||||
/// über „Bearbeiten“ (nur mit „Professioneller Netzwerker“). Bei leerem Ergebnis zeigt die View einen
|
||||
/// kurzen Hinweistext statt einer leeren Grafik.
|
||||
/// </summary>
|
||||
public partial class NetworkAnalysisStepViewModel : WizardStepViewModelBase
|
||||
{
|
||||
@@ -61,7 +57,6 @@ public partial class NetworkAnalysisStepViewModel : WizardStepViewModelBase
|
||||
|
||||
public override bool CanGoNext => !IsLoading;
|
||||
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.SetupWizard;
|
||||
|
||||
public override async Task OnActivatedAsync()
|
||||
{
|
||||
|
||||
@@ -14,9 +14,8 @@ namespace MikrotikInstaller.App.ViewModels.Steps;
|
||||
/// <summary>
|
||||
/// Letzter Schritt: zeigt alle in den vorherigen Schritten geplanten Änderungen im Klartext an.
|
||||
/// Erst wenn der Nutzer hier ausdrücklich "Jetzt einrichten" klickt, wird ein Backup erstellt und
|
||||
/// werden die Änderungen tatsächlich auf dem Gerät angewendet. Bei "Backup verwalten"
|
||||
/// (<see cref="AppArea.BackupManagement"/>) nicht relevant und übersprungen — dafür gibt es
|
||||
/// <see cref="BackupManagementStepViewModel"/>.
|
||||
/// werden die Änderungen tatsächlich auf dem Gerät angewendet. Enthält nur, was in
|
||||
/// besuchten Schritten gültig eingestellt wurde.
|
||||
/// </summary>
|
||||
public partial class SummaryStepViewModel : WizardStepViewModelBase
|
||||
{
|
||||
@@ -57,7 +56,6 @@ public partial class SummaryStepViewModel : WizardStepViewModelBase
|
||||
|
||||
public override bool CanGoNext => IsFinished;
|
||||
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.SetupWizard;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? _backupName;
|
||||
|
||||
@@ -28,8 +28,6 @@ public partial class VlanStepViewModel : WizardStepViewModelBase
|
||||
|
||||
public override bool CanGoNext => Vlans.All(IsValid);
|
||||
|
||||
/// <summary>Bei "Backup wiederherstellen" wird direkt zur Zusammenfassung gesprungen, ohne die Konfigurations-Schritte.</summary>
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.SetupWizard;
|
||||
|
||||
public override Task OnActivatedAsync()
|
||||
{
|
||||
|
||||
@@ -58,8 +58,6 @@ public partial class WanStepViewModel : WizardStepViewModelBase
|
||||
|
||||
public override bool CanGoNext => ValidationMessage is null;
|
||||
|
||||
/// <summary>Bei "Backup wiederherstellen" wird direkt zur Zusammenfassung gesprungen, ohne die Konfigurations-Schritte.</summary>
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.SetupWizard;
|
||||
|
||||
public override Task OnActivatedAsync()
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ public partial class WlanStepViewModel : WizardStepViewModelBase
|
||||
public bool IsExpertMode => _session.IsExpertMode;
|
||||
|
||||
/// <summary>Auch bei "Backup wiederherstellen" überspringen — nicht nur bei fehlendem WLAN.</summary>
|
||||
public override bool ShouldSkip => _session.SelectedArea != AppArea.SetupWizard || _session.Device?.HasWireless != true;
|
||||
public override bool ShouldSkip => _session.Device?.HasWireless != true;
|
||||
|
||||
public override bool CanGoNext =>
|
||||
SkipWireless
|
||||
|
||||
@@ -38,14 +38,6 @@ public sealed class WizardSession
|
||||
|
||||
private bool _isExpertMode;
|
||||
|
||||
/// <summary>
|
||||
/// Direkt nach dem Verbinden gewählter Bereich (siehe <see cref="Steps.AreaSelectionStepViewModel"/>).
|
||||
/// <see cref="AppArea.BackupManagement"/> überspringt den kompletten restlichen Assistenten
|
||||
/// (Geräte-Erkennung, IST-Zustand-Analyse, LAN-Scanner, Moduswahl, WAN/LAN/VLAN/WLAN/Firewall,
|
||||
/// Zusammenfassung) und führt direkt zur eigenständigen Backup-Verwaltung.
|
||||
/// </summary>
|
||||
public AppArea SelectedArea { get; set; } = AppArea.SetupWizard;
|
||||
|
||||
/// <summary>Vom WAN-Schritt gewählte Internet-Schnittstelle, damit spätere Schritte sie referenzieren können.</summary>
|
||||
public string? WanInterfaceName { get; set; }
|
||||
|
||||
@@ -159,6 +151,22 @@ public sealed class WizardSession
|
||||
client, Device?.BoardModel, Device?.Architecture, Device?.SerialNumber, UserSettings.BackupPassword);
|
||||
}
|
||||
|
||||
/// <summary>Vergisst den Einrichtungsplan des vorherigen Geräts, damit nach einem Gerätewechsel nichts davon angewendet wird.</summary>
|
||||
public void ResetPlan()
|
||||
{
|
||||
IsExpertMode = false;
|
||||
WanInterfaceName = LanBridgeName = null;
|
||||
WanActions = LanActions = VlanActions = WirelessActions = FirewallActions = null;
|
||||
WanSettings = null;
|
||||
LanSettings = null;
|
||||
VlanDefinitions = null;
|
||||
WirelessSettings = null;
|
||||
FirewallSettings = null;
|
||||
UpdateInfo = null;
|
||||
ExpertBackupDone = false;
|
||||
LastManualBackup = null;
|
||||
}
|
||||
|
||||
public async Task DisposeClientAsync()
|
||||
{
|
||||
if (Client is not null)
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<UserControl x:Class="MikrotikInstaller.App.Views.HelpView"
|
||||
xmlns:l="clr-namespace:MikrotikInstaller.App.Localization"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml">
|
||||
<TabControl Margin="0,16,0,0">
|
||||
<TabItem Header="{l:T 'Handbuch'}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="8,8,16,8">
|
||||
<ItemsControl ItemsSource="{Binding Manual}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock x:Name="Block" Text="{Binding Text}" TextWrapping="Wrap" Margin="0,0,0,8" />
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Heading1">
|
||||
<Setter TargetName="Block" Property="FontSize" Value="24" />
|
||||
<Setter TargetName="Block" Property="FontWeight" Value="SemiBold" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Heading2">
|
||||
<Setter TargetName="Block" Property="FontSize" Value="19" />
|
||||
<Setter TargetName="Block" Property="FontWeight" Value="SemiBold" />
|
||||
<Setter TargetName="Block" Property="Margin" Value="0,16,0,8" />
|
||||
<Setter TargetName="Block" Property="Foreground" Value="{StaticResource MikrotikAccentBrush}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Heading3">
|
||||
<Setter TargetName="Block" Property="FontSize" Value="15" />
|
||||
<Setter TargetName="Block" Property="FontWeight" Value="SemiBold" />
|
||||
<Setter TargetName="Block" Property="Margin" Value="0,10,0,6" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Bullet">
|
||||
<Setter TargetName="Block" Property="Margin" Value="16,0,0,6" />
|
||||
<Setter TargetName="Block" Property="Text" Value="{Binding Text, StringFormat=• {0}}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Numbered">
|
||||
<Setter TargetName="Block" Property="Margin" Value="16,0,0,6" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{l:T 'Begriffe'}">
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ui:TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" PlaceholderText="{l:T 'Begriff suchen, z. B. DHCP'}" Margin="0,0,0,12">
|
||||
<ui:TextBox.Icon>
|
||||
<ui:SymbolIcon Symbol="Search24" />
|
||||
</ui:TextBox.Icon>
|
||||
</ui:TextBox>
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl ItemsSource="{Binding Terms}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{DynamicResource ControlFillColorSecondaryBrush}" CornerRadius="6" Padding="12,8" Margin="0,0,8,8">
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding Title}" FontWeight="SemiBold" />
|
||||
<TextBlock Text="{Binding Text}" TextWrapping="Wrap" Margin="0,4,0,0" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace MikrotikInstaller.App.Views;
|
||||
|
||||
public partial class HelpView : System.Windows.Controls.UserControl
|
||||
{
|
||||
public HelpView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<ui:FluentWindow x:Class="MikrotikInstaller.App.Views.HelpWindow"
|
||||
xmlns:l="clr-namespace:MikrotikInstaller.App.Localization"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:vm="clr-namespace:MikrotikInstaller.App.ViewModels"
|
||||
Title="{l:T 'Hilfe'}" Width="820" Height="760"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ExtendsContentIntoTitleBar="True" WindowBackdropType="Mica">
|
||||
<Window.DataContext>
|
||||
<vm:HelpViewModel />
|
||||
</Window.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ui:TitleBar Grid.Row="0" Title="{l:T 'Hilfe — Handbuch und Begriffe'}" />
|
||||
|
||||
<TabControl Grid.Row="1" Margin="16,4,16,16">
|
||||
<TabItem Header="{l:T 'Handbuch'}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="8,8,16,8">
|
||||
<ItemsControl ItemsSource="{Binding Manual}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock x:Name="Block" Text="{Binding Text}" TextWrapping="Wrap" Margin="0,0,0,8" />
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Heading1">
|
||||
<Setter TargetName="Block" Property="FontSize" Value="24" />
|
||||
<Setter TargetName="Block" Property="FontWeight" Value="SemiBold" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Heading2">
|
||||
<Setter TargetName="Block" Property="FontSize" Value="19" />
|
||||
<Setter TargetName="Block" Property="FontWeight" Value="SemiBold" />
|
||||
<Setter TargetName="Block" Property="Margin" Value="0,16,0,8" />
|
||||
<Setter TargetName="Block" Property="Foreground" Value="{StaticResource MikrotikAccentBrush}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Heading3">
|
||||
<Setter TargetName="Block" Property="FontSize" Value="15" />
|
||||
<Setter TargetName="Block" Property="FontWeight" Value="SemiBold" />
|
||||
<Setter TargetName="Block" Property="Margin" Value="0,10,0,6" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Bullet">
|
||||
<Setter TargetName="Block" Property="Margin" Value="16,0,0,6" />
|
||||
<Setter TargetName="Block" Property="Text" Value="{Binding Text, StringFormat=• {0}}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Numbered">
|
||||
<Setter TargetName="Block" Property="Margin" Value="16,0,0,6" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{l:T 'Begriffe'}">
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ui:TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" PlaceholderText="{l:T 'Begriff suchen, z. B. DHCP'}" Margin="0,0,0,12">
|
||||
<ui:TextBox.Icon>
|
||||
<ui:SymbolIcon Symbol="Search24" />
|
||||
</ui:TextBox.Icon>
|
||||
</ui:TextBox>
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl ItemsSource="{Binding Terms}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{DynamicResource ControlFillColorSecondaryBrush}" CornerRadius="6" Padding="12,8" Margin="0,0,8,8">
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding Title}" FontWeight="SemiBold" />
|
||||
<TextBlock Text="{Binding Text}" TextWrapping="Wrap" Margin="0,4,0,0" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</Grid>
|
||||
</ui:FluentWindow>
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace MikrotikInstaller.App.Views;
|
||||
|
||||
public partial class HelpWindow : Wpf.Ui.Controls.FluentWindow
|
||||
{
|
||||
public HelpWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<UserControl x:Class="MikrotikInstaller.App.Views.SettingsView"
|
||||
xmlns:l="clr-namespace:MikrotikInstaller.App.Localization"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:controls="clr-namespace:MikrotikInstaller.App.Views.Controls">
|
||||
<StackPanel Margin="0,16,0,0" MaxWidth="560" HorizontalAlignment="Left">
|
||||
<TextBlock Text="{l:T 'Sprache'}" FontWeight="SemiBold" Margin="0,0,0,6" />
|
||||
<ComboBox ItemsSource="{Binding Languages}" DisplayMemberPath="Name" SelectedValuePath="Code"
|
||||
SelectedValue="{Binding Language}" HorizontalAlignment="Left" MinWidth="220" Margin="0,0,0,20" />
|
||||
<TextBlock Text="{l:T 'Darstellung'}" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8" />
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,20">
|
||||
<RadioButton Content="{l:T 'Wie System'}" GroupName="Theme" Margin="0,0,16,0"
|
||||
IsChecked="{Binding Theme, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=System}" />
|
||||
<RadioButton Content="{l:T 'Hell'}" GroupName="Theme" Margin="0,0,16,0"
|
||||
IsChecked="{Binding Theme, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Light}" />
|
||||
<RadioButton Content="{l:T 'Dunkel'}" GroupName="Theme"
|
||||
IsChecked="{Binding Theme, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Dark}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="{l:T 'Allgemein'}" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8" />
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<CheckBox Content="{l:T 'Beim Verbinden nach RouterOS-Updates suchen'}" IsChecked="{Binding CheckUpdatesOnConnect}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<CheckBox Content="{l:T 'Professioneller Netzwerker'}" IsChecked="{Binding ProfessionalMode}" />
|
||||
<controls:InfoHint Text="{l:T 'Blendet den Experten-Modus im Einrichtungs-Assistenten ein: zusätzliche, technischere RouterOS-Einstellungen in den einzelnen Schritten. Für die meisten Haushalte nicht nötig.'}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<CheckBox Content="{l:T 'Testumgebung anbieten'}" IsChecked="{Binding TestEnvironment}" />
|
||||
<controls:InfoHint Text="{l:T 'Zeigt im Verbindungs-Schritt simulierte Testgeräte, mit denen du den Assistenten ohne eigenen Router ausprobieren kannst. Änderungen bleiben nur bis zum Beenden der App erhalten.'}" />
|
||||
</StackPanel>
|
||||
<CheckBox Content="{l:T 'Einführung beim nächsten Start erneut zeigen'}" IsChecked="{Binding RestartIntro}" Margin="0,0,0,20" />
|
||||
|
||||
<TextBlock Text="{l:T 'Sicherungen'}" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8" />
|
||||
<TextBlock Text="{l:T 'Ordner für Backups auf diesem PC'}" Margin="0,0,0,4" />
|
||||
<Grid Margin="0,0,0,12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ui:TextBox Grid.Column="0" Text="{Binding BackupFolder, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ui:Button Grid.Column="1" Content="{l:T 'Wählen …'}" Margin="8,0,0,0" Command="{Binding ChooseBackupFolderCommand}" />
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,4">
|
||||
<TextBlock Text="{l:T 'Backup-Passwort'}" />
|
||||
<controls:InfoHint Text="{l:T 'Mit Passwort werden neue Backups von RouterOS verschlüsselt — auf dem Gerät und als Kopie auf diesem PC. Ohne das Passwort lassen sie sich nicht mehr zurückspielen, bewahre es also gut auf.'}" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="{l:T 'Ein Backup-Passwort ist gesetzt. Leer lassen, um es zu behalten.'}" FontSize="12" Margin="0,0,0,4"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
Visibility="{Binding HasBackupPassword, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<TextBlock Text="{l:T 'Kein Backup-Passwort gesetzt — neue Backups sind unverschlüsselt.'}" FontSize="12" Margin="0,0,0,4"
|
||||
Foreground="{StaticResource MikrotikWarningBrush}"
|
||||
Visibility="{Binding HasBackupPassword, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Invert}" />
|
||||
<ui:PasswordBox Password="{Binding NewBackupPassword, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="0,0,0,8" />
|
||||
<CheckBox Content="{l:T 'Backup-Passwort entfernen'}" IsChecked="{Binding RemoveBackupPassword}"
|
||||
Visibility="{Binding HasBackupPassword, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
|
||||
<ui:Button Content="{l:T 'Speichern'}" Appearance="Primary" Command="{Binding SaveCommand}" Margin="0,20,0,0" />
|
||||
<TextBlock Text="{Binding StatusMessage}" TextWrapping="Wrap" Foreground="{StaticResource MikrotikAccentBrush}" Margin="0,12,0,0"
|
||||
Visibility="{Binding StatusMessage, Converter={StaticResource StringToVisibilityConverter}}" />
|
||||
<TextBlock Text="{Binding ErrorMessage}" TextWrapping="Wrap" Foreground="{StaticResource MikrotikRedBrush}" Margin="0,12,0,0"
|
||||
Visibility="{Binding ErrorMessage, Converter={StaticResource StringToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace MikrotikInstaller.App.Views;
|
||||
|
||||
public partial class SettingsView : System.Windows.Controls.UserControl
|
||||
{
|
||||
public SettingsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
<ui:FluentWindow x:Class="MikrotikInstaller.App.Views.SettingsWindow"
|
||||
xmlns:l="clr-namespace:MikrotikInstaller.App.Localization"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:vm="clr-namespace:MikrotikInstaller.App.ViewModels"
|
||||
xmlns:controls="clr-namespace:MikrotikInstaller.App.Views.Controls"
|
||||
Title="{l:T 'Einstellungen'}" Width="560" Height="680"
|
||||
WindowStartupLocation="CenterOwner" ResizeMode="NoResize"
|
||||
ExtendsContentIntoTitleBar="True" WindowBackdropType="Mica">
|
||||
<Window.DataContext>
|
||||
<vm:SettingsViewModel />
|
||||
</Window.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ui:TitleBar Grid.Row="0" Title="{l:T 'Einstellungen'}" ShowMinimize="False" ShowMaximize="False" />
|
||||
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" Padding="28,8,28,8">
|
||||
<StackPanel>
|
||||
<TextBlock Text="{l:T 'Sprache'}" FontWeight="SemiBold" Margin="0,0,0,6" />
|
||||
<ComboBox ItemsSource="{Binding Languages}" DisplayMemberPath="Name" SelectedValuePath="Code"
|
||||
SelectedValue="{Binding Language}" HorizontalAlignment="Left" MinWidth="220" Margin="0,0,0,20" />
|
||||
<TextBlock Text="{l:T 'Darstellung'}" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8" />
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,20">
|
||||
<RadioButton Content="{l:T 'Wie System'}" GroupName="Theme" Margin="0,0,16,0"
|
||||
IsChecked="{Binding Theme, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=System}" />
|
||||
<RadioButton Content="{l:T 'Hell'}" GroupName="Theme" Margin="0,0,16,0"
|
||||
IsChecked="{Binding Theme, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Light}" />
|
||||
<RadioButton Content="{l:T 'Dunkel'}" GroupName="Theme"
|
||||
IsChecked="{Binding Theme, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Dark}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="{l:T 'Allgemein'}" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8" />
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<CheckBox Content="{l:T 'Beim Verbinden nach RouterOS-Updates suchen'}" IsChecked="{Binding CheckUpdatesOnConnect}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<CheckBox Content="{l:T 'Professioneller Netzwerker'}" IsChecked="{Binding ProfessionalMode}" />
|
||||
<controls:InfoHint Text="{l:T 'Blendet den Experten-Modus im Einrichtungs-Assistenten ein: zusätzliche, technischere RouterOS-Einstellungen in den einzelnen Schritten. Für die meisten Haushalte nicht nötig.'}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<CheckBox Content="{l:T 'Testumgebung anbieten'}" IsChecked="{Binding TestEnvironment}" />
|
||||
<controls:InfoHint Text="{l:T 'Zeigt im Verbindungs-Schritt simulierte Testgeräte, mit denen du den Assistenten ohne eigenen Router ausprobieren kannst. Änderungen bleiben nur bis zum Beenden der App erhalten.'}" />
|
||||
</StackPanel>
|
||||
<CheckBox Content="{l:T 'Einführung beim nächsten Start erneut zeigen'}" IsChecked="{Binding RestartIntro}" Margin="0,0,0,20" />
|
||||
|
||||
<TextBlock Text="{l:T 'Sicherungen'}" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8" />
|
||||
<TextBlock Text="{l:T 'Ordner für Backups auf diesem PC'}" Margin="0,0,0,4" />
|
||||
<Grid Margin="0,0,0,12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ui:TextBox Grid.Column="0" Text="{Binding BackupFolder, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ui:Button Grid.Column="1" Content="{l:T 'Wählen …'}" Margin="8,0,0,0" Command="{Binding ChooseBackupFolderCommand}" />
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,4">
|
||||
<TextBlock Text="{l:T 'Backup-Passwort'}" />
|
||||
<controls:InfoHint Text="{l:T 'Mit Passwort werden neue Backups von RouterOS verschlüsselt — auf dem Gerät und als Kopie auf diesem PC. Ohne das Passwort lassen sie sich nicht mehr zurückspielen, bewahre es also gut auf.'}" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="{l:T 'Ein Backup-Passwort ist gesetzt. Leer lassen, um es zu behalten.'}" FontSize="12" Margin="0,0,0,4"
|
||||
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
|
||||
Visibility="{Binding HasBackupPassword, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<TextBlock Text="{l:T 'Kein Backup-Passwort gesetzt — neue Backups sind unverschlüsselt.'}" FontSize="12" Margin="0,0,0,4"
|
||||
Foreground="{StaticResource MikrotikWarningBrush}"
|
||||
Visibility="{Binding HasBackupPassword, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Invert}" />
|
||||
<ui:PasswordBox Password="{Binding NewBackupPassword, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="0,0,0,8" />
|
||||
<CheckBox Content="{l:T 'Backup-Passwort entfernen'}" IsChecked="{Binding RemoveBackupPassword}"
|
||||
Visibility="{Binding HasBackupPassword, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
|
||||
<TextBlock Text="{Binding ErrorMessage}" TextWrapping="Wrap" Foreground="{StaticResource MikrotikRedBrush}" Margin="0,12,0,0"
|
||||
Visibility="{Binding ErrorMessage, Converter={StaticResource StringToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Border Grid.Row="2" BorderBrush="{DynamicResource DividerStrokeColorDefaultBrush}" BorderThickness="0,1,0,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="28,16">
|
||||
<ui:Button Content="{l:T 'Abbrechen'}" Margin="0,0,8,0" IsCancel="True" Click="OnCancel" />
|
||||
<ui:Button Content="{l:T 'Speichern'}" Appearance="Primary" IsDefault="True" Command="{Binding SaveCommand}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</ui:FluentWindow>
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Windows;
|
||||
using MikrotikInstaller.App.ViewModels;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace MikrotikInstaller.App.Views;
|
||||
|
||||
public partial class SettingsWindow : FluentWindow
|
||||
{
|
||||
public SettingsWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
((SettingsViewModel)DataContext).Saved += (_, _) => Close();
|
||||
}
|
||||
|
||||
private void OnCancel(object sender, RoutedEventArgs e) => Close();
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<UserControl x:Class="MikrotikInstaller.App.Views.SetupWizardView"
|
||||
xmlns:l="clr-namespace:MikrotikInstaller.App.Localization"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml">
|
||||
<!-- Eigene Scroll-Fläche, damit die Schrittleiste oben und Zurück/Weiter unten stehen bleiben. -->
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Schrittleiste: jeder Schritt direkt anklickbar -->
|
||||
<ItemsControl Grid.Row="0" ItemsSource="{Binding StepNavItems}" Margin="0,12,0,4">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ui:Button Appearance="Transparent" Padding="8,6" Margin="0,0,4,4"
|
||||
Command="{Binding DataContext.GoToStepCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
|
||||
CommandParameter="{Binding Number}">
|
||||
<ui:Button.Style>
|
||||
<Style TargetType="ui:Button" BasedOn="{StaticResource {x:Type ui:Button}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource MikrotikAccentSoftBrush}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ui:Button.Style>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Border Width="22" Height="22" CornerRadius="11" Margin="0,0,8,0">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="{DynamicResource ControlStrongFillColorDisabledBrush}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsCompleted}" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource MikrotikAccentBrush}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource MikrotikAccentBrush}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding Number}" FontSize="11" FontWeight="SemiBold" Foreground="White"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Visibility="{Binding IsCompleted, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Invert}" />
|
||||
<ui:SymbolIcon Symbol="Checkmark24" FontSize="12" Foreground="White"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Visibility="{Binding IsCompleted, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<TextBlock Text="{Binding Title}" VerticalAlignment="Center">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</ui:Button>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" Padding="0,0,8,16">
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding CurrentStep.Title}" FontSize="20" FontWeight="SemiBold" Margin="0,12,0,0" />
|
||||
<ContentControl Content="{Binding CurrentStep}" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Border Grid.Row="2" BorderBrush="{DynamicResource DividerStrokeColorDefaultBrush}" BorderThickness="0,1,0,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,16,0,20">
|
||||
<ui:Button Content="{l:T 'Zurück'}" Command="{Binding GoBackCommand}" Margin="0,0,8,0" />
|
||||
<ui:Button Content="{l:T 'Weiter'}" Appearance="Primary" Command="{Binding GoNextCommand}"
|
||||
Visibility="{Binding IsLastStep, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Invert}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace MikrotikInstaller.App.Views;
|
||||
|
||||
public partial class SetupWizardView : System.Windows.Controls.UserControl
|
||||
{
|
||||
public SetupWizardView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<UserControl x:Class="MikrotikInstaller.App.Views.StartView"
|
||||
xmlns:l="clr-namespace:MikrotikInstaller.App.Localization"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:vm="clr-namespace:MikrotikInstaller.App.ViewModels">
|
||||
<UserControl.Resources>
|
||||
<Style x:Key="QuickTile" TargetType="ui:Button" BasedOn="{StaticResource {x:Type ui:Button}}">
|
||||
<Setter Property="Command" Value="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType=Window}}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
<Setter Property="Padding" Value="14,12" />
|
||||
<Setter Property="Margin" Value="0,0,8,8" />
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<StackPanel Margin="0,16,0,0">
|
||||
<TextBlock Text="{Binding Description}" TextWrapping="Wrap" Margin="0,0,0,16" Opacity="0.8" />
|
||||
|
||||
<UniformGrid Columns="4" Margin="0,0,-8,8">
|
||||
<ui:Button Style="{StaticResource QuickTile}" CommandParameter="{x:Static vm:AppArea.Setup}">
|
||||
<StackPanel>
|
||||
<ui:SymbolIcon Symbol="Wand24" FontSize="22" HorizontalAlignment="Left" Foreground="{StaticResource MikrotikAccentBrush}" />
|
||||
<TextBlock Text="{l:T 'Einrichten'}" FontWeight="SemiBold" Margin="0,6,0,0" />
|
||||
<TextBlock Text="{l:T 'Internet, Heimnetz, WLAN, Firewall'}" FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</ui:Button>
|
||||
<ui:Button Style="{StaticResource QuickTile}" CommandParameter="{x:Static vm:AppArea.Overview}">
|
||||
<StackPanel>
|
||||
<ui:SymbolIcon Symbol="Organization24" FontSize="22" HorizontalAlignment="Left" Foreground="{StaticResource MikrotikAccentBrush}" />
|
||||
<TextBlock Text="{l:T 'Übersicht'}" FontWeight="SemiBold" Margin="0,6,0,0" />
|
||||
<TextBlock Text="{l:T 'Vorhandene Netzwerke als Grafik'}" FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</ui:Button>
|
||||
<ui:Button Style="{StaticResource QuickTile}" CommandParameter="{x:Static vm:AppArea.Devices}">
|
||||
<StackPanel>
|
||||
<ui:SymbolIcon Symbol="Desktop24" FontSize="22" HorizontalAlignment="Left" Foreground="{StaticResource MikrotikAccentBrush}" />
|
||||
<TextBlock Text="{l:T 'Geräte'}" FontWeight="SemiBold" Margin="0,6,0,0" />
|
||||
<TextBlock Text="{l:T 'Wer ist im Netzwerk?'}" FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</ui:Button>
|
||||
<ui:Button Style="{StaticResource QuickTile}" CommandParameter="{x:Static vm:AppArea.Backup}">
|
||||
<StackPanel>
|
||||
<ui:SymbolIcon Symbol="ArrowSync24" FontSize="22" HorizontalAlignment="Left" Foreground="{StaticResource MikrotikAccentBrush}" />
|
||||
<TextBlock Text="{l:T 'Backup & Wartung'}" FontWeight="SemiBold" Margin="0,6,0,0" />
|
||||
<TextBlock Text="{l:T 'Sichern, Neustart, Firmware'}" FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</ui:Button>
|
||||
</UniformGrid>
|
||||
|
||||
<ContentControl Content="{Binding Device}" />
|
||||
|
||||
<TextBlock Text="{Binding Update.Title}" FontSize="20" FontWeight="SemiBold" Margin="0,28,0,0" />
|
||||
<ContentControl Content="{Binding Update}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace MikrotikInstaller.App.Views;
|
||||
|
||||
public partial class StartView : System.Windows.Controls.UserControl
|
||||
{
|
||||
public StartView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<UserControl x:Class="MikrotikInstaller.App.Views.Steps.AreaSelectionStepView"
|
||||
xmlns:l="clr-namespace:MikrotikInstaller.App.Localization"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="600">
|
||||
<StackPanel Margin="0,16,0,0">
|
||||
<TextBlock Text="{Binding Description}" TextWrapping="Wrap" Margin="0,0,0,24" Opacity="0.8" />
|
||||
|
||||
<Border BorderBrush="{DynamicResource DividerStrokeColorDefaultBrush}" BorderThickness="1" CornerRadius="6" Padding="16" Margin="0,0,0,12">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Grid.Column="0" GroupName="AppArea" VerticalAlignment="Top" Margin="0,2,12,0"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=SetupWizard}" />
|
||||
<StackPanel Grid.Column="1">
|
||||
<TextBlock Text="{l:T 'Einrichtungs-Assistent'}" FontWeight="SemiBold" />
|
||||
<TextBlock Text="{l:T 'Gerät komplett neu einrichten: Internet-Zugang, Heimnetzwerk, VLANs, WLAN und Firewall — Schritt für Schritt.'}" TextWrapping="Wrap" Opacity="0.8" Margin="0,4,0,0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Border BorderBrush="{DynamicResource DividerStrokeColorDefaultBrush}" BorderThickness="1" CornerRadius="6" Padding="16">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Grid.Column="0" GroupName="AppArea" VerticalAlignment="Top" Margin="0,2,12,0"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=BackupManagement}" />
|
||||
<StackPanel Grid.Column="1">
|
||||
<TextBlock Text="{l:T 'Backup & Wartung'}" FontWeight="SemiBold" />
|
||||
<TextBlock Text="{l:T 'Backups auflisten, erstellen oder zurückspielen, das Gerät neu starten, die Firmware aktualisieren oder auf Werkseinstellungen zurücksetzen. Überspringt den restlichen Einrichtungs-Assistenten komplett.'}" TextWrapping="Wrap" Opacity="0.8" Margin="0,4,0,0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Border BorderBrush="{DynamicResource DividerStrokeColorDefaultBrush}" BorderThickness="1" CornerRadius="6" Padding="16" Margin="0,12,0,0"
|
||||
Visibility="{Binding ShowExpert, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<RadioButton Grid.Column="0" GroupName="AppArea" VerticalAlignment="Top" Margin="0,2,12,0"
|
||||
IsChecked="{Binding Area, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Expert}" />
|
||||
<StackPanel Grid.Column="1">
|
||||
<TextBlock Text="{l:T 'Experte'}" FontWeight="SemiBold" />
|
||||
<TextBlock Text="{l:T 'Direkter Zugriff auf RouterOS-Menüs (Firewall, Interfaces, IP, DHCP, WLAN, System …) mit Erklärungen zu jedem Feld, dazu Werkzeuge wie „Netzwerke isolieren“, „Neues LAN anlegen“, „Port in Bridge einfügen“ und „Pakete“. Jede Änderung zeigt vorher den genauen Befehl.'}" TextWrapping="Wrap" Opacity="0.8" Margin="0,4,0,0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -1,11 +0,0 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MikrotikInstaller.App.Views.Steps;
|
||||
|
||||
public partial class AreaSelectionStepView : UserControl
|
||||
{
|
||||
public AreaSelectionStepView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -55,10 +55,6 @@
|
||||
"en": "Starting with RouterOS 7.1rc4, enabling or changing this setting also requires a physical button press (Reset or Mode button) on the device itself within 60 seconds to confirm — a change through this app alone isn't enough.",
|
||||
"pt": "A partir do RouterOS 7.1rc4, ativar ou alterar esta configuração também exige pressionar fisicamente um botão (Reset ou Mode) no próprio dispositivo em até 60 segundos para confirmar — uma alteração apenas por este app não basta."
|
||||
},
|
||||
"Abbrechen": {
|
||||
"en": "Cancel",
|
||||
"pt": "Cancelar"
|
||||
},
|
||||
"Ablaufzeit": {
|
||||
"en": "Expiry",
|
||||
"pt": "Validade"
|
||||
@@ -355,10 +351,6 @@
|
||||
"en": "List, create or restore backups — and restart the device, update the firmware or reset it to factory settings.",
|
||||
"pt": "Listar, criar ou restaurar backups — e reiniciar o dispositivo, atualizar o firmware ou redefinir para as configurações de fábrica."
|
||||
},
|
||||
"Backups auflisten, erstellen oder zurückspielen, das Gerät neu starten, die Firmware aktualisieren oder auf Werkseinstellungen zurücksetzen. Überspringt den restlichen Einrichtungs-Assistenten komplett.": {
|
||||
"en": "List, create or restore backups, restart the device, update the firmware or reset it to factory settings. Skips the rest of the setup wizard completely.",
|
||||
"pt": "Listar, criar ou restaurar backups, reiniciar o dispositivo, atualizar o firmware ou redefinir para as configurações de fábrica. Pula completamente o restante do assistente de configuração."
|
||||
},
|
||||
"Backups werden ausgelesen …": {
|
||||
"en": "Reading backups …",
|
||||
"pt": "Lendo backups …"
|
||||
@@ -379,10 +371,6 @@
|
||||
"en": "Edit",
|
||||
"pt": "Editar"
|
||||
},
|
||||
"Beenden": {
|
||||
"en": "Finish",
|
||||
"pt": "Concluir"
|
||||
},
|
||||
"Begrenzt Up-/Download einer IP-Adresse oder eines Netzes.": {
|
||||
"en": "Limits upload/download of an IP address or a network.",
|
||||
"pt": "Limita upload/download de um endereço IP ou de uma rede."
|
||||
@@ -755,6 +743,10 @@
|
||||
"en": "Disabled",
|
||||
"pt": "Desativado"
|
||||
},
|
||||
"Dein Gerät auf einen Blick. Wähle links oder hier unten, was du tun möchtest.": {
|
||||
"en": "Your device at a glance. Choose on the left or below what you want to do.",
|
||||
"pt": "Seu dispositivo em um relance. Escolha à esquerda ou abaixo o que deseja fazer."
|
||||
},
|
||||
"Dein Gerät hat zwar eine WLAN-Schnittstelle, sie bleibt aber unangetastet und wird nicht eingerichtet, wenn du hier ein Häkchen setzt.": {
|
||||
"en": "Your device has a Wi-Fi interface, but if you tick this it stays untouched and is not set up.",
|
||||
"pt": "Seu dispositivo tem uma interface Wi-Fi, mas, se você marcar esta opção, ela fica intocada e não é configurada."
|
||||
@@ -1019,10 +1011,6 @@
|
||||
"en": "Isolate this network",
|
||||
"pt": "Isolar esta rede"
|
||||
},
|
||||
"Direkter Zugriff auf RouterOS-Menüs (Firewall, Interfaces, IP, DHCP, WLAN, System …) mit Erklärungen zu jedem Feld, dazu Werkzeuge wie „Netzwerke isolieren“, „Neues LAN anlegen“, „Port in Bridge einfügen“ und „Pakete“. Jede Änderung zeigt vorher den genauen Befehl.": {
|
||||
"en": "Direct access to RouterOS menus (firewall, interfaces, IP, DHCP, Wi-Fi, system …) with explanations for every field, plus tools like \"Isolate networks\", \"Create new LAN\", \"Add port to bridge\" and \"Packages\". Every change shows the exact command first.",
|
||||
"pt": "Acesso direto aos menus do RouterOS (firewall, interfaces, IP, DHCP, Wi-Fi, sistema …) com explicações para cada campo, além de ferramentas como \"Isolar redes\", \"Criar nova LAN\", \"Adicionar porta à bridge\" e \"Pacotes\". Cada alteração mostra antes o comando exato."
|
||||
},
|
||||
"Direkter Zugriff auf RouterOS-Menüs. Jede Änderung zeigt vorher den genauen Befehl; vor der ersten Änderung wird eine Sicherung erstellt.": {
|
||||
"en": "Direct access to RouterOS menus. Every change shows the exact command first; a backup is created before the first change.",
|
||||
"pt": "Acesso direto aos menus do RouterOS. Cada alteração mostra antes o comando exato; um backup é criado antes da primeira alteração."
|
||||
@@ -1147,9 +1135,9 @@
|
||||
"en": "Incoming Interface",
|
||||
"pt": "Interface de entrada"
|
||||
},
|
||||
"Einrichtungs-Assistent": {
|
||||
"en": "Setup wizard",
|
||||
"pt": "Assistente de configuração"
|
||||
"Einrichten": {
|
||||
"en": "Set up",
|
||||
"pt": "Configurar"
|
||||
},
|
||||
"Einrichtungsprotokoll speichern": {
|
||||
"en": "Save setup report",
|
||||
@@ -1603,10 +1591,6 @@
|
||||
"en": "Planned steps",
|
||||
"pt": "Etapas planejadas"
|
||||
},
|
||||
"Gerät komplett neu einrichten: Internet-Zugang, Heimnetzwerk, VLANs, WLAN und Firewall — Schritt für Schritt.": {
|
||||
"en": "Set up the device from scratch: internet access, home network, VLANs, Wi-Fi and firewall — step by step.",
|
||||
"pt": "Configurar o dispositivo do zero: acesso à internet, rede doméstica, VLANs, Wi-Fi e firewall — passo a passo."
|
||||
},
|
||||
"Gerät nicht erreichbar. Bitte über „Wechseln“ neu verbinden.": {
|
||||
"en": "Device not reachable. Please reconnect via \"Switch\".",
|
||||
"pt": "Dispositivo inacessível. Reconecte via \"Trocar\"."
|
||||
@@ -1623,6 +1607,10 @@
|
||||
"en": "Reading device …",
|
||||
"pt": "Lendo dispositivo …"
|
||||
},
|
||||
"Geräte": {
|
||||
"en": "Devices",
|
||||
"pt": "Dispositivos"
|
||||
},
|
||||
"Geräte an gebrückten Ports verhalten sich, als hingen sie am selben Netzwerk-Kabel. Eine IP-Adresse wird meist auf die Bridge selbst gelegt, nicht auf die einzelnen Ports.": {
|
||||
"en": "Devices on bridged ports behave as if they hung off the same network cable. An IP address usually goes on the bridge itself, not on the individual ports.",
|
||||
"pt": "Dispositivos em portas da bridge se comportam como se estivessem no mesmo cabo de rede. Um endereço IP normalmente vai na própria bridge, não nas portas individuais."
|
||||
@@ -1667,6 +1655,10 @@
|
||||
"en": "Saved to: ",
|
||||
"pt": "Salvo em: "
|
||||
},
|
||||
"Gespeichert.": {
|
||||
"en": "Saved.",
|
||||
"pt": "Salvo."
|
||||
},
|
||||
"Gespeichert: {0}": {
|
||||
"en": "Saved: {0}",
|
||||
"pt": "Salvo: {0}"
|
||||
@@ -1731,18 +1723,10 @@
|
||||
"en": "Light",
|
||||
"pt": "Claro"
|
||||
},
|
||||
"Hilfe": {
|
||||
"en": "Help",
|
||||
"pt": "Ajuda"
|
||||
},
|
||||
"Hilfe & Begriffe": {
|
||||
"en": "Help & terms",
|
||||
"pt": "Ajuda e termos"
|
||||
},
|
||||
"Hilfe — Handbuch und Begriffe": {
|
||||
"en": "Help — manual and terms",
|
||||
"pt": "Ajuda — manual e termos"
|
||||
},
|
||||
"Holt einen Anschluss (auch WLAN), der ein eigenes Netz hatte, zurück ins Heimnetz: Adresse, DHCP und Isolationsregeln dieses Anschlusses werden entfernt.": {
|
||||
"en": "Returns a port (Wi-Fi too) that had its own network to the home network: address, DHCP and isolation rules of this port are removed.",
|
||||
"pt": "Devolve à rede doméstica uma porta (inclusive Wi-Fi) que tinha rede própria: endereço, DHCP e regras de isolamento dessa porta são removidos."
|
||||
@@ -1939,6 +1923,10 @@
|
||||
"en": "Internet",
|
||||
"pt": "Internet"
|
||||
},
|
||||
"Internet, Heimnetz, WLAN, Firewall": {
|
||||
"en": "Internet, home network, Wi-Fi, firewall",
|
||||
"pt": "Internet, rede doméstica, Wi-Fi, firewall"
|
||||
},
|
||||
"Internet-Schnittstelle": {
|
||||
"en": "Internet interface",
|
||||
"pt": "Interface de internet"
|
||||
@@ -2443,10 +2431,6 @@
|
||||
"en": "New backups are stored unencrypted. You can set a backup password in the settings.",
|
||||
"pt": "Os novos backups são salvos sem criptografia. Você pode definir uma senha de backup nas configurações."
|
||||
},
|
||||
"Neue Verbindung im ersten Schritt einrichten.": {
|
||||
"en": "Set up a new connection in the first step.",
|
||||
"pt": "Configure uma nova conexão na primeira etapa."
|
||||
},
|
||||
"Neuer Eintrag": {
|
||||
"en": "New entry",
|
||||
"pt": "Nova entrada"
|
||||
@@ -2851,6 +2835,10 @@
|
||||
"en": "Permission Group",
|
||||
"pt": "Grupo de permissões"
|
||||
},
|
||||
"Rechts eine neue Verbindung einrichten.": {
|
||||
"en": "Set up a new connection on the right.",
|
||||
"pt": "Configure uma nova conexão à direita."
|
||||
},
|
||||
"Regel inaktiv schalten, ohne sie zu löschen.": {
|
||||
"en": "Turn the rule off without deleting it.",
|
||||
"pt": "Desliga a regra sem excluí-la."
|
||||
@@ -2983,10 +2971,6 @@
|
||||
"en": "Step 1 of {0}: create backup on the device",
|
||||
"pt": "Etapa 1 de {0}: criar backup no dispositivo"
|
||||
},
|
||||
"Schritt {0} von {1}": {
|
||||
"en": "Step {0} of {1}",
|
||||
"pt": "Etapa {0} de {1}"
|
||||
},
|
||||
"Schritt {0} von {1}: {2}": {
|
||||
"en": "Step {0} of {1}: {2}",
|
||||
"pt": "Etapa {0} de {1}: {2}"
|
||||
@@ -3015,6 +2999,10 @@
|
||||
"en": "Security Profile",
|
||||
"pt": "Perfil de segurança"
|
||||
},
|
||||
"Sichern, Neustart, Firmware": {
|
||||
"en": "Back up, restart, firmware",
|
||||
"pt": "Backup, reinício, firmware"
|
||||
},
|
||||
"Sicherung des aktuellen Zustands wird erstellt …": {
|
||||
"en": "Creating a backup of the current state …",
|
||||
"pt": "Criando um backup do estado atual …"
|
||||
@@ -3103,6 +3091,10 @@
|
||||
"en": "Adopt Default Route",
|
||||
"pt": "Adotar rota padrão"
|
||||
},
|
||||
"Start": {
|
||||
"en": "Home",
|
||||
"pt": "Início"
|
||||
},
|
||||
"Startet den Router neu. Die Verbindung bricht kurz ab, der Assistent verbindet sich danach von selbst wieder.": {
|
||||
"en": "Restarts the router. The connection drops briefly; the wizard reconnects on its own afterwards.",
|
||||
"pt": "Reinicia o roteador. A conexão cai por pouco tempo; depois o assistente se reconecta sozinho."
|
||||
@@ -3255,6 +3247,10 @@
|
||||
"en": "Processing point in the router's internal packet flow.",
|
||||
"pt": "Ponto de processamento no fluxo interno de pacotes do roteador."
|
||||
},
|
||||
"Verbinden": {
|
||||
"en": "Connect",
|
||||
"pt": "Conectar"
|
||||
},
|
||||
"Verbindung": {
|
||||
"en": "Connection",
|
||||
"pt": "Conexão"
|
||||
@@ -3343,6 +3339,10 @@
|
||||
"en": "Existing networks",
|
||||
"pt": "Redes existentes"
|
||||
},
|
||||
"Vorhandene Netzwerke als Grafik": {
|
||||
"en": "Existing networks as a diagram",
|
||||
"pt": "Redes existentes como diagrama"
|
||||
},
|
||||
"Vorhandenes Heimnetz „{0}“ ({1}) vom Router übernommen. Beim Anwenden werden diese Einträge aktualisiert statt neu angelegt.": {
|
||||
"en": "Existing home network \"{0}\" ({1}) taken over from the router. When applying, these entries are updated instead of created anew.",
|
||||
"pt": "A rede doméstica existente \"{0}\" ({1}) foi carregada do roteador. Ao aplicar, essas entradas são atualizadas em vez de criadas de novo."
|
||||
@@ -3447,10 +3447,6 @@
|
||||
"en": "What happens to matching packets. reject also sends back an error message, drop discards silently.",
|
||||
"pt": "O que acontece com os pacotes correspondentes. reject também envia uma mensagem de erro de volta, drop descarta silenciosamente."
|
||||
},
|
||||
"Was möchtest du tun?": {
|
||||
"en": "What would you like to do?",
|
||||
"pt": "O que você deseja fazer?"
|
||||
},
|
||||
"Webseiten, die Gäste schon vor der Anmeldung erreichen (z.B. Impressum, Bezahlseite).": {
|
||||
"en": "Websites guests can reach before logging in (e.g. legal notice, payment page).",
|
||||
"pt": "Sites que os convidados acessam antes do login (ex.: termos legais, página de pagamento)."
|
||||
@@ -3503,6 +3499,10 @@
|
||||
"en": "Which management service is being changed.",
|
||||
"pt": "Qual serviço de gerenciamento está sendo alterado."
|
||||
},
|
||||
"Wer ist im Netzwerk?": {
|
||||
"en": "Who is on the network?",
|
||||
"pt": "Quem está na rede?"
|
||||
},
|
||||
"Werkseinstellungen wiederherstellen": {
|
||||
"en": "Restore Factory Defaults",
|
||||
"pt": "Restaurar configurações de fábrica"
|
||||
@@ -3603,10 +3603,6 @@
|
||||
"en": "Choose the interface your internet cable (from your provider's modem/router) is connected to.",
|
||||
"pt": "Escolha a interface onde está ligado o cabo de internet (do modem/roteador do seu provedor)."
|
||||
},
|
||||
"Wähle, ob du dein Gerät komplett neu einrichten oder Backups und Wartung erledigen möchtest.": {
|
||||
"en": "Choose whether you want to set up your device completely or take care of backups and maintenance.",
|
||||
"pt": "Escolha se deseja configurar o dispositivo por completo ou cuidar de backups e manutenção."
|
||||
},
|
||||
"Wähle, welche Anschlüsse zu deinem Heimnetzwerk gehören sollen, und lege den IP-Adressbereich fest. Die Vorgaben passen für die meisten Haushalte.": {
|
||||
"en": "Choose which ports should belong to your home network and set the IP address range. The defaults suit most households.",
|
||||
"pt": "Escolha quais portas pertencem à sua rede doméstica e defina a faixa de endereços IP. Os valores padrão servem para a maioria das casas."
|
||||
@@ -3963,6 +3959,10 @@
|
||||
"en": "Translates internet addresses like 'google.com' into the number behind them. The default suits most people – you don't need to change anything here.",
|
||||
"pt": "Traduz endereços da internet como 'google.com' no número por trás deles. O padrão serve para a maioria – você não precisa mudar nada aqui."
|
||||
},
|
||||
"Übersicht": {
|
||||
"en": "Overview",
|
||||
"pt": "Visão geral"
|
||||
},
|
||||
"Überspringen": {
|
||||
"en": "Skip",
|
||||
"pt": "Pular"
|
||||
|
||||
Reference in new issue
Block a user