diff --git a/.github/workflows/build-multiplatform.yml b/.github/workflows/build-multiplatform.yml
index cb27a2e..084bfde 100644
--- a/.github/workflows/build-multiplatform.yml
+++ b/.github/workflows/build-multiplatform.yml
@@ -583,8 +583,15 @@ jobs:
id: commits
run: |
# Get last 10 commit messages with hash and date
- git log -10 --pretty=format:'{"hash":"%h","date":"%ci","message":"%s","author":"%an"}' | \
- jq -s '.' > commits.json
+ # Use jq to properly escape all strings
+ git log -10 --pretty=format:'%h|%ci|%s|%an' | while IFS='|' read -r hash date message author; do
+ jq -n \
+ --arg hash "$hash" \
+ --arg date "$date" \
+ --arg message "$message" \
+ --arg author "$author" \
+ '{hash: $hash, date: $date, message: $message, author: $author}'
+ done | jq -s '.' > commits.json
# Also create a simple text version for easier parsing
git log -10 --pretty=format:'%h|%ci|%s|%an' > commits.txt
@@ -1099,6 +1106,13 @@ jobs:
// Embedded commits data (no fetch needed)
const commitsData = ${COMMITS_DATA};
+ // HTML escape function to prevent XSS
+ function escapeHtml(text) {
+ const div = document.createElement('div');
+ div.textContent = text;
+ return div.innerHTML;
+ }
+
// Display commits
(function() {
const list = document.getElementById('commits-list');
@@ -1120,11 +1134,11 @@ jobs:
return \`
-
\${commit.message}
-
by \${commit.author}
+
\${escapeHtml(commit.message)}
+
by \${escapeHtml(commit.author)}
\`;
}).join('');
diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb
index b13cb33..8634009 100644
--- a/lib/l10n/app_de.arb
+++ b/lib/l10n/app_de.arb
@@ -2728,5 +2728,38 @@
"channelCreatedSuccessfully": "Kanal erfolgreich erstellt",
"channelCreationFailed": "Kanal konnte nicht erstellt werden: {error}",
"allChannelSlotsInUse": "Alle Kanalplätze sind belegt (maximal 39 benutzerdefinierte Kanäle)",
- "createChannel": "Kanal erstellen"
+ "createChannel": "Kanal erstellen",
+
+ "wizardBack": "Zurück",
+ "wizardSkip": "Überspringen",
+ "wizardNext": "Weiter",
+ "wizardGetStarted": "Loslegen",
+ "wizardWelcomeTitle": "Willkommen bei MeshCore SAR",
+ "wizardWelcomeDescription": "Ein leistungsstarkes Offline-Kommunikationstool für Such- und Rettungseinsätze. Verbinden Sie sich mit Ihrem Team über Mesh-Funktechnologie, wenn herkömmliche Netzwerke nicht verfügbar sind.",
+ "wizardConnectingTitle": "Verbindung zum Radio",
+ "wizardConnectingDescription": "Verbinden Sie Ihr Smartphone über Bluetooth mit einem MeshCore-Funkgerät, um offline zu kommunizieren.",
+ "wizardConnectingFeature1": "Nach MeshCore-Geräten in der Nähe suchen",
+ "wizardConnectingFeature2": "Mit Ihrem Funkgerät über Bluetooth koppeln",
+ "wizardConnectingFeature3": "Funktioniert vollständig offline - kein Internet erforderlich",
+ "wizardSimpleModeTitle": "Einfacher Modus",
+ "wizardSimpleModeDescription": "Neu im Mesh-Netzwerk? Aktivieren Sie den einfachen Modus für eine optimierte Benutzeroberfläche mit nur wesentlichen Funktionen.",
+ "wizardSimpleModeFeature1": "Anfängerfreundliche Benutzeroberfläche mit Kernfunktionen",
+ "wizardSimpleModeFeature2": "Jederzeit in den erweiterten Modus in den Einstellungen wechseln",
+ "wizardChannelTitle": "Kanäle",
+ "wizardChannelDescription": "Senden Sie Nachrichten an alle auf einem Kanal, perfekt für teamweite Ankündigungen und Koordination.",
+ "wizardChannelFeature1": "Öffentlicher Kanal für allgemeine Teamkommunikation",
+ "wizardChannelFeature2": "Erstellen Sie benutzerdefinierte Kanäle für bestimmte Gruppen",
+ "wizardChannelFeature3": "Nachrichten werden automatisch über das Mesh weitergeleitet",
+ "wizardContactsTitle": "Kontakte",
+ "wizardContactsDescription": "Ihre Teammitglieder erscheinen automatisch, wenn sie dem Mesh-Netzwerk beitreten. Senden Sie ihnen direkte Nachrichten oder sehen Sie ihren Standort.",
+ "wizardContactsFeature1": "Kontakte werden automatisch erkannt",
+ "wizardContactsFeature2": "Private Direktnachrichten senden",
+ "wizardContactsFeature3": "Batteriestand und letzte Aktivität anzeigen",
+ "wizardMapTitle": "Karte & Standort",
+ "wizardMapDescription": "Verfolgen Sie Ihr Team in Echtzeit und markieren Sie wichtige Standorte für Such- und Rettungseinsätze.",
+ "wizardMapFeature1": "SAR-Markierungen für gefundene Personen, Feuer und Sammelstellen",
+ "wizardMapFeature2": "GPS-Verfolgung von Teammitgliedern in Echtzeit",
+ "wizardMapFeature3": "Offline-Karten für entlegene Gebiete herunterladen",
+ "wizardMapFeature4": "Formen zeichnen und taktische Informationen teilen",
+ "viewWelcomeTutorial": "Willkommens-Tutorial ansehen"
}
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index 0f85723..5277cfc 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -3426,5 +3426,165 @@
"createChannel": "Create Channel",
"@createChannel": {
"description": "Button text for creating a channel"
+ },
+
+ "wizardBack": "Back",
+ "@wizardBack": {
+ "description": "Wizard back button text"
+ },
+
+ "wizardSkip": "Skip",
+ "@wizardSkip": {
+ "description": "Wizard skip button text"
+ },
+
+ "wizardNext": "Next",
+ "@wizardNext": {
+ "description": "Wizard next button text"
+ },
+
+ "wizardGetStarted": "Get Started",
+ "@wizardGetStarted": {
+ "description": "Wizard final button text to complete onboarding"
+ },
+
+ "wizardWelcomeTitle": "Welcome to MeshCore SAR",
+ "@wizardWelcomeTitle": {
+ "description": "Welcome wizard first page title"
+ },
+
+ "wizardWelcomeDescription": "A powerful off-grid communication tool for search and rescue operations. Connect with your team using mesh radio technology when traditional networks are unavailable.",
+ "@wizardWelcomeDescription": {
+ "description": "Welcome wizard first page description"
+ },
+
+ "wizardConnectingTitle": "Connecting to Your Radio",
+ "@wizardConnectingTitle": {
+ "description": "Wizard connecting page title"
+ },
+
+ "wizardConnectingDescription": "Connect your smartphone to a MeshCore radio device via Bluetooth to start communicating off-grid.",
+ "@wizardConnectingDescription": {
+ "description": "Wizard connecting page description"
+ },
+
+ "wizardConnectingFeature1": "Scan for nearby MeshCore devices",
+ "@wizardConnectingFeature1": {
+ "description": "Wizard connecting feature 1"
+ },
+
+ "wizardConnectingFeature2": "Pair with your radio via Bluetooth",
+ "@wizardConnectingFeature2": {
+ "description": "Wizard connecting feature 2"
+ },
+
+ "wizardConnectingFeature3": "Works completely offline - no internet required",
+ "@wizardConnectingFeature3": {
+ "description": "Wizard connecting feature 3"
+ },
+
+ "wizardSimpleModeTitle": "Simple Mode",
+ "@wizardSimpleModeTitle": {
+ "description": "Wizard simple mode page title"
+ },
+
+ "wizardSimpleModeDescription": "New to mesh networking? Enable Simple Mode for a streamlined interface with essential features only.",
+ "@wizardSimpleModeDescription": {
+ "description": "Wizard simple mode page description"
+ },
+
+ "wizardSimpleModeFeature1": "Beginner-friendly interface with core functions",
+ "@wizardSimpleModeFeature1": {
+ "description": "Wizard simple mode feature 1"
+ },
+
+ "wizardSimpleModeFeature2": "Switch to Advanced Mode anytime in Settings",
+ "@wizardSimpleModeFeature2": {
+ "description": "Wizard simple mode feature 2"
+ },
+
+ "wizardChannelTitle": "Channels",
+ "@wizardChannelTitle": {
+ "description": "Wizard channel page title"
+ },
+
+ "wizardChannelDescription": "Broadcast messages to everyone on a channel, perfect for team-wide announcements and coordination.",
+ "@wizardChannelDescription": {
+ "description": "Wizard channel page description"
+ },
+
+ "wizardChannelFeature1": "Public Channel for general team communication",
+ "@wizardChannelFeature1": {
+ "description": "Wizard channel feature 1"
+ },
+
+ "wizardChannelFeature2": "Create custom channels for specific groups",
+ "@wizardChannelFeature2": {
+ "description": "Wizard channel feature 2"
+ },
+
+ "wizardChannelFeature3": "Messages are automatically relayed by the mesh",
+ "@wizardChannelFeature3": {
+ "description": "Wizard channel feature 3"
+ },
+
+ "wizardContactsTitle": "Contacts",
+ "@wizardContactsTitle": {
+ "description": "Wizard contacts page title"
+ },
+
+ "wizardContactsDescription": "Your team members appear automatically as they join the mesh network. Send them direct messages or view their location.",
+ "@wizardContactsDescription": {
+ "description": "Wizard contacts page description"
+ },
+
+ "wizardContactsFeature1": "Contacts discovered automatically",
+ "@wizardContactsFeature1": {
+ "description": "Wizard contacts feature 1"
+ },
+
+ "wizardContactsFeature2": "Send private direct messages",
+ "@wizardContactsFeature2": {
+ "description": "Wizard contacts feature 2"
+ },
+
+ "wizardContactsFeature3": "View battery level and last seen time",
+ "@wizardContactsFeature3": {
+ "description": "Wizard contacts feature 3"
+ },
+
+ "wizardMapTitle": "Map & Location",
+ "@wizardMapTitle": {
+ "description": "Wizard map page title"
+ },
+
+ "wizardMapDescription": "Track your team in real-time and mark important locations for search and rescue operations.",
+ "@wizardMapDescription": {
+ "description": "Wizard map page description"
+ },
+
+ "wizardMapFeature1": "SAR markers for found persons, fires, and staging areas",
+ "@wizardMapFeature1": {
+ "description": "Wizard map feature 1"
+ },
+
+ "wizardMapFeature2": "Real-time GPS tracking of team members",
+ "@wizardMapFeature2": {
+ "description": "Wizard map feature 2"
+ },
+
+ "wizardMapFeature3": "Download offline maps for remote areas",
+ "@wizardMapFeature3": {
+ "description": "Wizard map feature 3"
+ },
+
+ "wizardMapFeature4": "Draw shapes and share tactical information",
+ "@wizardMapFeature4": {
+ "description": "Wizard map feature 4"
+ },
+
+ "viewWelcomeTutorial": "View Welcome Tutorial",
+ "@viewWelcomeTutorial": {
+ "description": "Settings option to re-show welcome wizard"
}
}
diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb
index 0dd57cf..efe2888 100644
--- a/lib/l10n/app_es.arb
+++ b/lib/l10n/app_es.arb
@@ -2723,5 +2723,38 @@
"channelCreatedSuccessfully": "Canal creado exitosamente",
"channelCreationFailed": "Error al crear el canal: {error}",
"allChannelSlotsInUse": "Todos los espacios de canales están en uso (máximo 39 canales personalizados)",
- "createChannel": "Crear Canal"
+ "createChannel": "Crear Canal",
+
+ "wizardBack": "Atrás",
+ "wizardSkip": "Omitir",
+ "wizardNext": "Siguiente",
+ "wizardGetStarted": "Comenzar",
+ "wizardWelcomeTitle": "Bienvenido a MeshCore SAR",
+ "wizardWelcomeDescription": "Una poderosa herramienta de comunicación sin conexión para operaciones de búsqueda y rescate. Conéctese con su equipo usando tecnología de radio en malla cuando las redes tradicionales no estén disponibles.",
+ "wizardConnectingTitle": "Conectando a su Radio",
+ "wizardConnectingDescription": "Conecte su smartphone a un dispositivo de radio MeshCore vía Bluetooth para comenzar a comunicarse sin conexión.",
+ "wizardConnectingFeature1": "Buscar dispositivos MeshCore cercanos",
+ "wizardConnectingFeature2": "Emparejar con su radio vía Bluetooth",
+ "wizardConnectingFeature3": "Funciona completamente sin conexión - no se requiere internet",
+ "wizardSimpleModeTitle": "Modo Simple",
+ "wizardSimpleModeDescription": "¿Nuevo en redes en malla? Habilite el modo simple para una interfaz optimizada con solo funciones esenciales.",
+ "wizardSimpleModeFeature1": "Interfaz amigable para principiantes con funciones principales",
+ "wizardSimpleModeFeature2": "Cambie al modo avanzado en cualquier momento en Configuración",
+ "wizardChannelTitle": "Canales",
+ "wizardChannelDescription": "Transmita mensajes a todos en un canal, perfecto para anuncios y coordinación de todo el equipo.",
+ "wizardChannelFeature1": "Canal público para comunicación general del equipo",
+ "wizardChannelFeature2": "Cree canales personalizados para grupos específicos",
+ "wizardChannelFeature3": "Los mensajes se retransmiten automáticamente por la malla",
+ "wizardContactsTitle": "Contactos",
+ "wizardContactsDescription": "Los miembros de su equipo aparecen automáticamente cuando se unen a la red en malla. Envíeles mensajes directos o vea su ubicación.",
+ "wizardContactsFeature1": "Contactos descubiertos automáticamente",
+ "wizardContactsFeature2": "Enviar mensajes directos privados",
+ "wizardContactsFeature3": "Ver nivel de batería y hora de última vista",
+ "wizardMapTitle": "Mapa & Ubicación",
+ "wizardMapDescription": "Rastree a su equipo en tiempo real y marque ubicaciones importantes para operaciones de búsqueda y rescate.",
+ "wizardMapFeature1": "Marcadores SAR para personas encontradas, incendios y áreas de preparación",
+ "wizardMapFeature2": "Rastreo GPS en tiempo real de miembros del equipo",
+ "wizardMapFeature3": "Descargar mapas sin conexión para áreas remotas",
+ "wizardMapFeature4": "Dibujar formas y compartir información táctica",
+ "viewWelcomeTutorial": "Ver tutorial de bienvenida"
}
diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb
index 27744db..4fc448a 100644
--- a/lib/l10n/app_fr.arb
+++ b/lib/l10n/app_fr.arb
@@ -2731,5 +2731,38 @@
"channelCreatedSuccessfully": "Canal créé avec succès",
"channelCreationFailed": "Échec de la création du canal : {error}",
"allChannelSlotsInUse": "Tous les emplacements de canaux sont utilisés (maximum 39 canaux personnalisés)",
- "createChannel": "Créer un Canal"
+ "createChannel": "Créer un Canal",
+
+ "wizardBack": "Retour",
+ "wizardSkip": "Passer",
+ "wizardNext": "Suivant",
+ "wizardGetStarted": "Commencer",
+ "wizardWelcomeTitle": "Bienvenue dans MeshCore SAR",
+ "wizardWelcomeDescription": "Un outil de communication hors ligne puissant pour les opérations de recherche et de sauvetage. Connectez-vous avec votre équipe en utilisant la technologie radio maillée lorsque les réseaux traditionnels ne sont pas disponibles.",
+ "wizardConnectingTitle": "Connexion à votre Radio",
+ "wizardConnectingDescription": "Connectez votre smartphone à un appareil radio MeshCore via Bluetooth pour commencer à communiquer hors ligne.",
+ "wizardConnectingFeature1": "Rechercher les appareils MeshCore à proximité",
+ "wizardConnectingFeature2": "Coupler avec votre radio via Bluetooth",
+ "wizardConnectingFeature3": "Fonctionne entièrement hors ligne - aucun internet requis",
+ "wizardSimpleModeTitle": "Mode Simple",
+ "wizardSimpleModeDescription": "Nouveau dans les réseaux maillés ? Activez le mode simple pour une interface simplifiée avec seulement les fonctions essentielles.",
+ "wizardSimpleModeFeature1": "Interface conviviale pour débutants avec les fonctions principales",
+ "wizardSimpleModeFeature2": "Passer en mode avancé à tout moment dans les paramètres",
+ "wizardChannelTitle": "Canaux",
+ "wizardChannelDescription": "Diffusez des messages à tous sur un canal, parfait pour les annonces et la coordination de toute l'équipe.",
+ "wizardChannelFeature1": "Canal public pour la communication générale de l'équipe",
+ "wizardChannelFeature2": "Créer des canaux personnalisés pour des groupes spécifiques",
+ "wizardChannelFeature3": "Les messages sont automatiquement relayés par le maillage",
+ "wizardContactsTitle": "Contacts",
+ "wizardContactsDescription": "Les membres de votre équipe apparaissent automatiquement lorsqu'ils rejoignent le réseau maillé. Envoyez-leur des messages directs ou consultez leur emplacement.",
+ "wizardContactsFeature1": "Contacts découverts automatiquement",
+ "wizardContactsFeature2": "Envoyer des messages directs privés",
+ "wizardContactsFeature3": "Voir le niveau de batterie et l'heure de dernière vue",
+ "wizardMapTitle": "Carte & Localisation",
+ "wizardMapDescription": "Suivez votre équipe en temps réel et marquez les emplacements importants pour les opérations de recherche et de sauvetage.",
+ "wizardMapFeature1": "Marqueurs SAR pour les personnes retrouvées, les incendies et les zones de rassemblement",
+ "wizardMapFeature2": "Suivi GPS en temps réel des membres de l'équipe",
+ "wizardMapFeature3": "Télécharger des cartes hors ligne pour les zones éloignées",
+ "wizardMapFeature4": "Dessiner des formes et partager des informations tactiques",
+ "viewWelcomeTutorial": "Voir le tutoriel de bienvenue"
}
diff --git a/lib/l10n/app_hr.arb b/lib/l10n/app_hr.arb
index 6a44a94..863a4bc 100644
--- a/lib/l10n/app_hr.arb
+++ b/lib/l10n/app_hr.arb
@@ -1029,5 +1029,38 @@
"channelCreatedSuccessfully": "Kanal uspješno kreiran",
"channelCreationFailed": "Neuspješno kreiranje kanala: {error}",
"allChannelSlotsInUse": "Svi slotovi kanala su zauzeti (maksimalno 39 prilagođenih kanala)",
- "createChannel": "Kreiraj kanal"
+ "createChannel": "Kreiraj kanal",
+
+ "wizardBack": "Natrag",
+ "wizardSkip": "Preskoči",
+ "wizardNext": "Dalje",
+ "wizardGetStarted": "Započni",
+ "wizardWelcomeTitle": "Dobrodošli u MeshCore SAR",
+ "wizardWelcomeDescription": "Moćan alat za komunikaciju bez mreže za spasilačke operacije. Povežite se sa svojim timom koristeći mesh radio tehnologiju kada tradicionalne mreže nisu dostupne.",
+ "wizardConnectingTitle": "Povezivanje s Radiom",
+ "wizardConnectingDescription": "Povežite svoj pametni telefon s MeshCore radio uređajem putem Bluetootha kako biste započeli komunikaciju bez mreže.",
+ "wizardConnectingFeature1": "Skeniraj obližnje MeshCore uređaje",
+ "wizardConnectingFeature2": "Uparite se s vašim radiom putem Bluetootha",
+ "wizardConnectingFeature3": "Radi potpuno offline - internet nije potreban",
+ "wizardSimpleModeTitle": "Jednostavan Način",
+ "wizardSimpleModeDescription": "Novi u mesh umrežavanju? Omogućite jednostavan način za pojednostavljeno sučelje samo s bitnim funkcijama.",
+ "wizardSimpleModeFeature1": "Sučelje prijateljsko početnicima s osnovnim funkcijama",
+ "wizardSimpleModeFeature2": "Prebacite na Napredni način bilo kada u Postavkama",
+ "wizardChannelTitle": "Kanali",
+ "wizardChannelDescription": "Emitirajte poruke svima na kanalu, savršeno za objave i koordinaciju cijele ekipe.",
+ "wizardChannelFeature1": "Javni kanal za opću komunikaciju ekipe",
+ "wizardChannelFeature2": "Stvorite prilagođene kanale za specifične grupe",
+ "wizardChannelFeature3": "Poruke se automatski prosljeđuju putem mreže",
+ "wizardContactsTitle": "Kontakti",
+ "wizardContactsDescription": "Vaši članovi tima se automatski pojavljuju kada se pridruže mesh mreži. Pošaljite im direktne poruke ili pogledajte njihovu lokaciju.",
+ "wizardContactsFeature1": "Kontakti se automatski otkrivaju",
+ "wizardContactsFeature2": "Šaljite privatne direktne poruke",
+ "wizardContactsFeature3": "Pogledajte razinu baterije i vrijeme zadnjeg viđenja",
+ "wizardMapTitle": "Karta & Lokacija",
+ "wizardMapDescription": "Pratite svoj tim u stvarnom vremenu i označite važne lokacije za spasilačke operacije.",
+ "wizardMapFeature1": "SAR oznake za pronađene osobe, požare i područja postavljanja",
+ "wizardMapFeature2": "GPS praćenje članova tima u stvarnom vremenu",
+ "wizardMapFeature3": "Preuzmite offline karte za udaljena područja",
+ "wizardMapFeature4": "Crtajte oblike i dijelite taktičke informacije",
+ "viewWelcomeTutorial": "Pogledaj uputu dobrodošlice"
}
diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb
index d005f5e..45190f7 100644
--- a/lib/l10n/app_it.arb
+++ b/lib/l10n/app_it.arb
@@ -2731,5 +2731,38 @@
"channelCreatedSuccessfully": "Canale creato con successo",
"channelCreationFailed": "Creazione del canale fallita: {error}",
"allChannelSlotsInUse": "Tutti gli slot dei canali sono in uso (massimo 39 canali personalizzati)",
- "createChannel": "Crea Canale"
+ "createChannel": "Crea Canale",
+
+ "wizardBack": "Indietro",
+ "wizardSkip": "Salta",
+ "wizardNext": "Avanti",
+ "wizardGetStarted": "Inizia",
+ "wizardWelcomeTitle": "Benvenuto in MeshCore SAR",
+ "wizardWelcomeDescription": "Un potente strumento di comunicazione offline per operazioni di ricerca e soccorso. Connettiti con il tuo team usando la tecnologia radio mesh quando le reti tradizionali non sono disponibili.",
+ "wizardConnectingTitle": "Connessione alla Radio",
+ "wizardConnectingDescription": "Collega il tuo smartphone a un dispositivo radio MeshCore tramite Bluetooth per iniziare a comunicare offline.",
+ "wizardConnectingFeature1": "Cerca dispositivi MeshCore nelle vicinanze",
+ "wizardConnectingFeature2": "Accoppia con la tua radio tramite Bluetooth",
+ "wizardConnectingFeature3": "Funziona completamente offline - non è richiesta connessione internet",
+ "wizardSimpleModeTitle": "Modalità Semplice",
+ "wizardSimpleModeDescription": "Nuovo alle reti mesh? Abilita la modalità semplice per un'interfaccia semplificata con solo le funzioni essenziali.",
+ "wizardSimpleModeFeature1": "Interfaccia intuitiva per principianti con funzioni principali",
+ "wizardSimpleModeFeature2": "Passa alla modalità avanzata in qualsiasi momento dalle Impostazioni",
+ "wizardChannelTitle": "Canali",
+ "wizardChannelDescription": "Trasmetti messaggi a tutti su un canale, perfetto per annunci e coordinamento di tutto il team.",
+ "wizardChannelFeature1": "Canale pubblico per comunicazione generale del team",
+ "wizardChannelFeature2": "Crea canali personalizzati per gruppi specifici",
+ "wizardChannelFeature3": "I messaggi vengono automaticamente inoltrati attraverso la rete mesh",
+ "wizardContactsTitle": "Contatti",
+ "wizardContactsDescription": "I membri del tuo team appaiono automaticamente quando si uniscono alla rete mesh. Invia loro messaggi diretti o visualizza la loro posizione.",
+ "wizardContactsFeature1": "Contatti scoperti automaticamente",
+ "wizardContactsFeature2": "Invia messaggi diretti privati",
+ "wizardContactsFeature3": "Visualizza livello batteria e ultima volta visto",
+ "wizardMapTitle": "Mappa & Posizione",
+ "wizardMapDescription": "Traccia il tuo team in tempo reale e segna posizioni importanti per operazioni di ricerca e soccorso.",
+ "wizardMapFeature1": "Marcatori SAR per persone trovate, incendi e aree di staging",
+ "wizardMapFeature2": "Tracciamento GPS in tempo reale dei membri del team",
+ "wizardMapFeature3": "Scarica mappe offline per aree remote",
+ "wizardMapFeature4": "Disegna forme e condividi informazioni tattiche",
+ "viewWelcomeTutorial": "Visualizza tutorial di benvenuto"
}
diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart
index a373d3e..2ca7381 100644
--- a/lib/l10n/app_localizations.dart
+++ b/lib/l10n/app_localizations.dart
@@ -3650,6 +3650,198 @@ abstract class AppLocalizations {
/// In en, this message translates to:
/// **'Create Channel'**
String get createChannel;
+
+ /// Wizard back button text
+ ///
+ /// In en, this message translates to:
+ /// **'Back'**
+ String get wizardBack;
+
+ /// Wizard skip button text
+ ///
+ /// In en, this message translates to:
+ /// **'Skip'**
+ String get wizardSkip;
+
+ /// Wizard next button text
+ ///
+ /// In en, this message translates to:
+ /// **'Next'**
+ String get wizardNext;
+
+ /// Wizard final button text to complete onboarding
+ ///
+ /// In en, this message translates to:
+ /// **'Get Started'**
+ String get wizardGetStarted;
+
+ /// Welcome wizard first page title
+ ///
+ /// In en, this message translates to:
+ /// **'Welcome to MeshCore SAR'**
+ String get wizardWelcomeTitle;
+
+ /// Welcome wizard first page description
+ ///
+ /// In en, this message translates to:
+ /// **'A powerful off-grid communication tool for search and rescue operations. Connect with your team using mesh radio technology when traditional networks are unavailable.'**
+ String get wizardWelcomeDescription;
+
+ /// Wizard connecting page title
+ ///
+ /// In en, this message translates to:
+ /// **'Connecting to Your Radio'**
+ String get wizardConnectingTitle;
+
+ /// Wizard connecting page description
+ ///
+ /// In en, this message translates to:
+ /// **'Connect your smartphone to a MeshCore radio device via Bluetooth to start communicating off-grid.'**
+ String get wizardConnectingDescription;
+
+ /// Wizard connecting feature 1
+ ///
+ /// In en, this message translates to:
+ /// **'Scan for nearby MeshCore devices'**
+ String get wizardConnectingFeature1;
+
+ /// Wizard connecting feature 2
+ ///
+ /// In en, this message translates to:
+ /// **'Pair with your radio via Bluetooth'**
+ String get wizardConnectingFeature2;
+
+ /// Wizard connecting feature 3
+ ///
+ /// In en, this message translates to:
+ /// **'Works completely offline - no internet required'**
+ String get wizardConnectingFeature3;
+
+ /// Wizard simple mode page title
+ ///
+ /// In en, this message translates to:
+ /// **'Simple Mode'**
+ String get wizardSimpleModeTitle;
+
+ /// Wizard simple mode page description
+ ///
+ /// In en, this message translates to:
+ /// **'New to mesh networking? Enable Simple Mode for a streamlined interface with essential features only.'**
+ String get wizardSimpleModeDescription;
+
+ /// Wizard simple mode feature 1
+ ///
+ /// In en, this message translates to:
+ /// **'Beginner-friendly interface with core functions'**
+ String get wizardSimpleModeFeature1;
+
+ /// Wizard simple mode feature 2
+ ///
+ /// In en, this message translates to:
+ /// **'Switch to Advanced Mode anytime in Settings'**
+ String get wizardSimpleModeFeature2;
+
+ /// Wizard channel page title
+ ///
+ /// In en, this message translates to:
+ /// **'Channels'**
+ String get wizardChannelTitle;
+
+ /// Wizard channel page description
+ ///
+ /// In en, this message translates to:
+ /// **'Broadcast messages to everyone on a channel, perfect for team-wide announcements and coordination.'**
+ String get wizardChannelDescription;
+
+ /// Wizard channel feature 1
+ ///
+ /// In en, this message translates to:
+ /// **'Public Channel for general team communication'**
+ String get wizardChannelFeature1;
+
+ /// Wizard channel feature 2
+ ///
+ /// In en, this message translates to:
+ /// **'Create custom channels for specific groups'**
+ String get wizardChannelFeature2;
+
+ /// Wizard channel feature 3
+ ///
+ /// In en, this message translates to:
+ /// **'Messages are automatically relayed by the mesh'**
+ String get wizardChannelFeature3;
+
+ /// Wizard contacts page title
+ ///
+ /// In en, this message translates to:
+ /// **'Contacts'**
+ String get wizardContactsTitle;
+
+ /// Wizard contacts page description
+ ///
+ /// In en, this message translates to:
+ /// **'Your team members appear automatically as they join the mesh network. Send them direct messages or view their location.'**
+ String get wizardContactsDescription;
+
+ /// Wizard contacts feature 1
+ ///
+ /// In en, this message translates to:
+ /// **'Contacts discovered automatically'**
+ String get wizardContactsFeature1;
+
+ /// Wizard contacts feature 2
+ ///
+ /// In en, this message translates to:
+ /// **'Send private direct messages'**
+ String get wizardContactsFeature2;
+
+ /// Wizard contacts feature 3
+ ///
+ /// In en, this message translates to:
+ /// **'View battery level and last seen time'**
+ String get wizardContactsFeature3;
+
+ /// Wizard map page title
+ ///
+ /// In en, this message translates to:
+ /// **'Map & Location'**
+ String get wizardMapTitle;
+
+ /// Wizard map page description
+ ///
+ /// In en, this message translates to:
+ /// **'Track your team in real-time and mark important locations for search and rescue operations.'**
+ String get wizardMapDescription;
+
+ /// Wizard map feature 1
+ ///
+ /// In en, this message translates to:
+ /// **'SAR markers for found persons, fires, and staging areas'**
+ String get wizardMapFeature1;
+
+ /// Wizard map feature 2
+ ///
+ /// In en, this message translates to:
+ /// **'Real-time GPS tracking of team members'**
+ String get wizardMapFeature2;
+
+ /// Wizard map feature 3
+ ///
+ /// In en, this message translates to:
+ /// **'Download offline maps for remote areas'**
+ String get wizardMapFeature3;
+
+ /// Wizard map feature 4
+ ///
+ /// In en, this message translates to:
+ /// **'Draw shapes and share tactical information'**
+ String get wizardMapFeature4;
+
+ /// Settings option to re-show welcome wizard
+ ///
+ /// In en, this message translates to:
+ /// **'View Welcome Tutorial'**
+ String get viewWelcomeTutorial;
}
class _AppLocalizationsDelegate
diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart
index 55f26aa..1600466 100644
--- a/lib/l10n/app_localizations_de.dart
+++ b/lib/l10n/app_localizations_de.dart
@@ -2042,4 +2042,119 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get createChannel => 'Kanal erstellen';
+
+ @override
+ String get wizardBack => 'Zurück';
+
+ @override
+ String get wizardSkip => 'Überspringen';
+
+ @override
+ String get wizardNext => 'Weiter';
+
+ @override
+ String get wizardGetStarted => 'Loslegen';
+
+ @override
+ String get wizardWelcomeTitle => 'Willkommen bei MeshCore SAR';
+
+ @override
+ String get wizardWelcomeDescription =>
+ 'Ein leistungsstarkes Offline-Kommunikationstool für Such- und Rettungseinsätze. Verbinden Sie sich mit Ihrem Team über Mesh-Funktechnologie, wenn herkömmliche Netzwerke nicht verfügbar sind.';
+
+ @override
+ String get wizardConnectingTitle => 'Verbindung zum Radio';
+
+ @override
+ String get wizardConnectingDescription =>
+ 'Verbinden Sie Ihr Smartphone über Bluetooth mit einem MeshCore-Funkgerät, um offline zu kommunizieren.';
+
+ @override
+ String get wizardConnectingFeature1 =>
+ 'Nach MeshCore-Geräten in der Nähe suchen';
+
+ @override
+ String get wizardConnectingFeature2 =>
+ 'Mit Ihrem Funkgerät über Bluetooth koppeln';
+
+ @override
+ String get wizardConnectingFeature3 =>
+ 'Funktioniert vollständig offline - kein Internet erforderlich';
+
+ @override
+ String get wizardSimpleModeTitle => 'Einfacher Modus';
+
+ @override
+ String get wizardSimpleModeDescription =>
+ 'Neu im Mesh-Netzwerk? Aktivieren Sie den einfachen Modus für eine optimierte Benutzeroberfläche mit nur wesentlichen Funktionen.';
+
+ @override
+ String get wizardSimpleModeFeature1 =>
+ 'Anfängerfreundliche Benutzeroberfläche mit Kernfunktionen';
+
+ @override
+ String get wizardSimpleModeFeature2 =>
+ 'Jederzeit in den erweiterten Modus in den Einstellungen wechseln';
+
+ @override
+ String get wizardChannelTitle => 'Kanäle';
+
+ @override
+ String get wizardChannelDescription =>
+ 'Senden Sie Nachrichten an alle auf einem Kanal, perfekt für teamweite Ankündigungen und Koordination.';
+
+ @override
+ String get wizardChannelFeature1 =>
+ 'Öffentlicher Kanal für allgemeine Teamkommunikation';
+
+ @override
+ String get wizardChannelFeature2 =>
+ 'Erstellen Sie benutzerdefinierte Kanäle für bestimmte Gruppen';
+
+ @override
+ String get wizardChannelFeature3 =>
+ 'Nachrichten werden automatisch über das Mesh weitergeleitet';
+
+ @override
+ String get wizardContactsTitle => 'Kontakte';
+
+ @override
+ String get wizardContactsDescription =>
+ 'Ihre Teammitglieder erscheinen automatisch, wenn sie dem Mesh-Netzwerk beitreten. Senden Sie ihnen direkte Nachrichten oder sehen Sie ihren Standort.';
+
+ @override
+ String get wizardContactsFeature1 => 'Kontakte werden automatisch erkannt';
+
+ @override
+ String get wizardContactsFeature2 => 'Private Direktnachrichten senden';
+
+ @override
+ String get wizardContactsFeature3 =>
+ 'Batteriestand und letzte Aktivität anzeigen';
+
+ @override
+ String get wizardMapTitle => 'Karte & Standort';
+
+ @override
+ String get wizardMapDescription =>
+ 'Verfolgen Sie Ihr Team in Echtzeit und markieren Sie wichtige Standorte für Such- und Rettungseinsätze.';
+
+ @override
+ String get wizardMapFeature1 =>
+ 'SAR-Markierungen für gefundene Personen, Feuer und Sammelstellen';
+
+ @override
+ String get wizardMapFeature2 =>
+ 'GPS-Verfolgung von Teammitgliedern in Echtzeit';
+
+ @override
+ String get wizardMapFeature3 =>
+ 'Offline-Karten für entlegene Gebiete herunterladen';
+
+ @override
+ String get wizardMapFeature4 =>
+ 'Formen zeichnen und taktische Informationen teilen';
+
+ @override
+ String get viewWelcomeTutorial => 'Willkommens-Tutorial ansehen';
}
diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart
index 2129c27..a669f26 100644
--- a/lib/l10n/app_localizations_en.dart
+++ b/lib/l10n/app_localizations_en.dart
@@ -2021,4 +2021,113 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get createChannel => 'Create Channel';
+
+ @override
+ String get wizardBack => 'Back';
+
+ @override
+ String get wizardSkip => 'Skip';
+
+ @override
+ String get wizardNext => 'Next';
+
+ @override
+ String get wizardGetStarted => 'Get Started';
+
+ @override
+ String get wizardWelcomeTitle => 'Welcome to MeshCore SAR';
+
+ @override
+ String get wizardWelcomeDescription =>
+ 'A powerful off-grid communication tool for search and rescue operations. Connect with your team using mesh radio technology when traditional networks are unavailable.';
+
+ @override
+ String get wizardConnectingTitle => 'Connecting to Your Radio';
+
+ @override
+ String get wizardConnectingDescription =>
+ 'Connect your smartphone to a MeshCore radio device via Bluetooth to start communicating off-grid.';
+
+ @override
+ String get wizardConnectingFeature1 => 'Scan for nearby MeshCore devices';
+
+ @override
+ String get wizardConnectingFeature2 => 'Pair with your radio via Bluetooth';
+
+ @override
+ String get wizardConnectingFeature3 =>
+ 'Works completely offline - no internet required';
+
+ @override
+ String get wizardSimpleModeTitle => 'Simple Mode';
+
+ @override
+ String get wizardSimpleModeDescription =>
+ 'New to mesh networking? Enable Simple Mode for a streamlined interface with essential features only.';
+
+ @override
+ String get wizardSimpleModeFeature1 =>
+ 'Beginner-friendly interface with core functions';
+
+ @override
+ String get wizardSimpleModeFeature2 =>
+ 'Switch to Advanced Mode anytime in Settings';
+
+ @override
+ String get wizardChannelTitle => 'Channels';
+
+ @override
+ String get wizardChannelDescription =>
+ 'Broadcast messages to everyone on a channel, perfect for team-wide announcements and coordination.';
+
+ @override
+ String get wizardChannelFeature1 =>
+ 'Public Channel for general team communication';
+
+ @override
+ String get wizardChannelFeature2 =>
+ 'Create custom channels for specific groups';
+
+ @override
+ String get wizardChannelFeature3 =>
+ 'Messages are automatically relayed by the mesh';
+
+ @override
+ String get wizardContactsTitle => 'Contacts';
+
+ @override
+ String get wizardContactsDescription =>
+ 'Your team members appear automatically as they join the mesh network. Send them direct messages or view their location.';
+
+ @override
+ String get wizardContactsFeature1 => 'Contacts discovered automatically';
+
+ @override
+ String get wizardContactsFeature2 => 'Send private direct messages';
+
+ @override
+ String get wizardContactsFeature3 => 'View battery level and last seen time';
+
+ @override
+ String get wizardMapTitle => 'Map & Location';
+
+ @override
+ String get wizardMapDescription =>
+ 'Track your team in real-time and mark important locations for search and rescue operations.';
+
+ @override
+ String get wizardMapFeature1 =>
+ 'SAR markers for found persons, fires, and staging areas';
+
+ @override
+ String get wizardMapFeature2 => 'Real-time GPS tracking of team members';
+
+ @override
+ String get wizardMapFeature3 => 'Download offline maps for remote areas';
+
+ @override
+ String get wizardMapFeature4 => 'Draw shapes and share tactical information';
+
+ @override
+ String get viewWelcomeTutorial => 'View Welcome Tutorial';
}
diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart
index 1617ffe..945fae9 100644
--- a/lib/l10n/app_localizations_es.dart
+++ b/lib/l10n/app_localizations_es.dart
@@ -2047,4 +2047,118 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get createChannel => 'Crear Canal';
+
+ @override
+ String get wizardBack => 'Atrás';
+
+ @override
+ String get wizardSkip => 'Omitir';
+
+ @override
+ String get wizardNext => 'Siguiente';
+
+ @override
+ String get wizardGetStarted => 'Comenzar';
+
+ @override
+ String get wizardWelcomeTitle => 'Bienvenido a MeshCore SAR';
+
+ @override
+ String get wizardWelcomeDescription =>
+ 'Una poderosa herramienta de comunicación sin conexión para operaciones de búsqueda y rescate. Conéctese con su equipo usando tecnología de radio en malla cuando las redes tradicionales no estén disponibles.';
+
+ @override
+ String get wizardConnectingTitle => 'Conectando a su Radio';
+
+ @override
+ String get wizardConnectingDescription =>
+ 'Conecte su smartphone a un dispositivo de radio MeshCore vía Bluetooth para comenzar a comunicarse sin conexión.';
+
+ @override
+ String get wizardConnectingFeature1 =>
+ 'Buscar dispositivos MeshCore cercanos';
+
+ @override
+ String get wizardConnectingFeature2 => 'Emparejar con su radio vía Bluetooth';
+
+ @override
+ String get wizardConnectingFeature3 =>
+ 'Funciona completamente sin conexión - no se requiere internet';
+
+ @override
+ String get wizardSimpleModeTitle => 'Modo Simple';
+
+ @override
+ String get wizardSimpleModeDescription =>
+ '¿Nuevo en redes en malla? Habilite el modo simple para una interfaz optimizada con solo funciones esenciales.';
+
+ @override
+ String get wizardSimpleModeFeature1 =>
+ 'Interfaz amigable para principiantes con funciones principales';
+
+ @override
+ String get wizardSimpleModeFeature2 =>
+ 'Cambie al modo avanzado en cualquier momento en Configuración';
+
+ @override
+ String get wizardChannelTitle => 'Canales';
+
+ @override
+ String get wizardChannelDescription =>
+ 'Transmita mensajes a todos en un canal, perfecto para anuncios y coordinación de todo el equipo.';
+
+ @override
+ String get wizardChannelFeature1 =>
+ 'Canal público para comunicación general del equipo';
+
+ @override
+ String get wizardChannelFeature2 =>
+ 'Cree canales personalizados para grupos específicos';
+
+ @override
+ String get wizardChannelFeature3 =>
+ 'Los mensajes se retransmiten automáticamente por la malla';
+
+ @override
+ String get wizardContactsTitle => 'Contactos';
+
+ @override
+ String get wizardContactsDescription =>
+ 'Los miembros de su equipo aparecen automáticamente cuando se unen a la red en malla. Envíeles mensajes directos o vea su ubicación.';
+
+ @override
+ String get wizardContactsFeature1 => 'Contactos descubiertos automáticamente';
+
+ @override
+ String get wizardContactsFeature2 => 'Enviar mensajes directos privados';
+
+ @override
+ String get wizardContactsFeature3 =>
+ 'Ver nivel de batería y hora de última vista';
+
+ @override
+ String get wizardMapTitle => 'Mapa & Ubicación';
+
+ @override
+ String get wizardMapDescription =>
+ 'Rastree a su equipo en tiempo real y marque ubicaciones importantes para operaciones de búsqueda y rescate.';
+
+ @override
+ String get wizardMapFeature1 =>
+ 'Marcadores SAR para personas encontradas, incendios y áreas de preparación';
+
+ @override
+ String get wizardMapFeature2 =>
+ 'Rastreo GPS en tiempo real de miembros del equipo';
+
+ @override
+ String get wizardMapFeature3 =>
+ 'Descargar mapas sin conexión para áreas remotas';
+
+ @override
+ String get wizardMapFeature4 =>
+ 'Dibujar formas y compartir información táctica';
+
+ @override
+ String get viewWelcomeTutorial => 'Ver tutorial de bienvenida';
}
diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart
index 5b3aefb..94f1825 100644
--- a/lib/l10n/app_localizations_fr.dart
+++ b/lib/l10n/app_localizations_fr.dart
@@ -2052,4 +2052,119 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get createChannel => 'Créer un Canal';
+
+ @override
+ String get wizardBack => 'Retour';
+
+ @override
+ String get wizardSkip => 'Passer';
+
+ @override
+ String get wizardNext => 'Suivant';
+
+ @override
+ String get wizardGetStarted => 'Commencer';
+
+ @override
+ String get wizardWelcomeTitle => 'Bienvenue dans MeshCore SAR';
+
+ @override
+ String get wizardWelcomeDescription =>
+ 'Un outil de communication hors ligne puissant pour les opérations de recherche et de sauvetage. Connectez-vous avec votre équipe en utilisant la technologie radio maillée lorsque les réseaux traditionnels ne sont pas disponibles.';
+
+ @override
+ String get wizardConnectingTitle => 'Connexion à votre Radio';
+
+ @override
+ String get wizardConnectingDescription =>
+ 'Connectez votre smartphone à un appareil radio MeshCore via Bluetooth pour commencer à communiquer hors ligne.';
+
+ @override
+ String get wizardConnectingFeature1 =>
+ 'Rechercher les appareils MeshCore à proximité';
+
+ @override
+ String get wizardConnectingFeature2 =>
+ 'Coupler avec votre radio via Bluetooth';
+
+ @override
+ String get wizardConnectingFeature3 =>
+ 'Fonctionne entièrement hors ligne - aucun internet requis';
+
+ @override
+ String get wizardSimpleModeTitle => 'Mode Simple';
+
+ @override
+ String get wizardSimpleModeDescription =>
+ 'Nouveau dans les réseaux maillés ? Activez le mode simple pour une interface simplifiée avec seulement les fonctions essentielles.';
+
+ @override
+ String get wizardSimpleModeFeature1 =>
+ 'Interface conviviale pour débutants avec les fonctions principales';
+
+ @override
+ String get wizardSimpleModeFeature2 =>
+ 'Passer en mode avancé à tout moment dans les paramètres';
+
+ @override
+ String get wizardChannelTitle => 'Canaux';
+
+ @override
+ String get wizardChannelDescription =>
+ 'Diffusez des messages à tous sur un canal, parfait pour les annonces et la coordination de toute l\'équipe.';
+
+ @override
+ String get wizardChannelFeature1 =>
+ 'Canal public pour la communication générale de l\'équipe';
+
+ @override
+ String get wizardChannelFeature2 =>
+ 'Créer des canaux personnalisés pour des groupes spécifiques';
+
+ @override
+ String get wizardChannelFeature3 =>
+ 'Les messages sont automatiquement relayés par le maillage';
+
+ @override
+ String get wizardContactsTitle => 'Contacts';
+
+ @override
+ String get wizardContactsDescription =>
+ 'Les membres de votre équipe apparaissent automatiquement lorsqu\'ils rejoignent le réseau maillé. Envoyez-leur des messages directs ou consultez leur emplacement.';
+
+ @override
+ String get wizardContactsFeature1 => 'Contacts découverts automatiquement';
+
+ @override
+ String get wizardContactsFeature2 => 'Envoyer des messages directs privés';
+
+ @override
+ String get wizardContactsFeature3 =>
+ 'Voir le niveau de batterie et l\'heure de dernière vue';
+
+ @override
+ String get wizardMapTitle => 'Carte & Localisation';
+
+ @override
+ String get wizardMapDescription =>
+ 'Suivez votre équipe en temps réel et marquez les emplacements importants pour les opérations de recherche et de sauvetage.';
+
+ @override
+ String get wizardMapFeature1 =>
+ 'Marqueurs SAR pour les personnes retrouvées, les incendies et les zones de rassemblement';
+
+ @override
+ String get wizardMapFeature2 =>
+ 'Suivi GPS en temps réel des membres de l\'équipe';
+
+ @override
+ String get wizardMapFeature3 =>
+ 'Télécharger des cartes hors ligne pour les zones éloignées';
+
+ @override
+ String get wizardMapFeature4 =>
+ 'Dessiner des formes et partager des informations tactiques';
+
+ @override
+ String get viewWelcomeTutorial => 'Voir le tutoriel de bienvenue';
}
diff --git a/lib/l10n/app_localizations_hr.dart b/lib/l10n/app_localizations_hr.dart
index cad6995..baa63c1 100644
--- a/lib/l10n/app_localizations_hr.dart
+++ b/lib/l10n/app_localizations_hr.dart
@@ -2030,4 +2030,117 @@ class AppLocalizationsHr extends AppLocalizations {
@override
String get createChannel => 'Kreiraj kanal';
+
+ @override
+ String get wizardBack => 'Natrag';
+
+ @override
+ String get wizardSkip => 'Preskoči';
+
+ @override
+ String get wizardNext => 'Dalje';
+
+ @override
+ String get wizardGetStarted => 'Započni';
+
+ @override
+ String get wizardWelcomeTitle => 'Dobrodošli u MeshCore SAR';
+
+ @override
+ String get wizardWelcomeDescription =>
+ 'Moćan alat za komunikaciju bez mreže za spasilačke operacije. Povežite se sa svojim timom koristeći mesh radio tehnologiju kada tradicionalne mreže nisu dostupne.';
+
+ @override
+ String get wizardConnectingTitle => 'Povezivanje s Radiom';
+
+ @override
+ String get wizardConnectingDescription =>
+ 'Povežite svoj pametni telefon s MeshCore radio uređajem putem Bluetootha kako biste započeli komunikaciju bez mreže.';
+
+ @override
+ String get wizardConnectingFeature1 => 'Skeniraj obližnje MeshCore uređaje';
+
+ @override
+ String get wizardConnectingFeature2 =>
+ 'Uparite se s vašim radiom putem Bluetootha';
+
+ @override
+ String get wizardConnectingFeature3 =>
+ 'Radi potpuno offline - internet nije potreban';
+
+ @override
+ String get wizardSimpleModeTitle => 'Jednostavan Način';
+
+ @override
+ String get wizardSimpleModeDescription =>
+ 'Novi u mesh umrežavanju? Omogućite jednostavan način za pojednostavljeno sučelje samo s bitnim funkcijama.';
+
+ @override
+ String get wizardSimpleModeFeature1 =>
+ 'Sučelje prijateljsko početnicima s osnovnim funkcijama';
+
+ @override
+ String get wizardSimpleModeFeature2 =>
+ 'Prebacite na Napredni način bilo kada u Postavkama';
+
+ @override
+ String get wizardChannelTitle => 'Kanali';
+
+ @override
+ String get wizardChannelDescription =>
+ 'Emitirajte poruke svima na kanalu, savršeno za objave i koordinaciju cijele ekipe.';
+
+ @override
+ String get wizardChannelFeature1 => 'Javni kanal za opću komunikaciju ekipe';
+
+ @override
+ String get wizardChannelFeature2 =>
+ 'Stvorite prilagođene kanale za specifične grupe';
+
+ @override
+ String get wizardChannelFeature3 =>
+ 'Poruke se automatski prosljeđuju putem mreže';
+
+ @override
+ String get wizardContactsTitle => 'Kontakti';
+
+ @override
+ String get wizardContactsDescription =>
+ 'Vaši članovi tima se automatski pojavljuju kada se pridruže mesh mreži. Pošaljite im direktne poruke ili pogledajte njihovu lokaciju.';
+
+ @override
+ String get wizardContactsFeature1 => 'Kontakti se automatski otkrivaju';
+
+ @override
+ String get wizardContactsFeature2 => 'Šaljite privatne direktne poruke';
+
+ @override
+ String get wizardContactsFeature3 =>
+ 'Pogledajte razinu baterije i vrijeme zadnjeg viđenja';
+
+ @override
+ String get wizardMapTitle => 'Karta & Lokacija';
+
+ @override
+ String get wizardMapDescription =>
+ 'Pratite svoj tim u stvarnom vremenu i označite važne lokacije za spasilačke operacije.';
+
+ @override
+ String get wizardMapFeature1 =>
+ 'SAR oznake za pronađene osobe, požare i područja postavljanja';
+
+ @override
+ String get wizardMapFeature2 =>
+ 'GPS praćenje članova tima u stvarnom vremenu';
+
+ @override
+ String get wizardMapFeature3 =>
+ 'Preuzmite offline karte za udaljena područja';
+
+ @override
+ String get wizardMapFeature4 =>
+ 'Crtajte oblike i dijelite taktičke informacije';
+
+ @override
+ String get viewWelcomeTutorial => 'Pogledaj uputu dobrodošlice';
}
diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart
index 9fadc29..25d5134 100644
--- a/lib/l10n/app_localizations_it.dart
+++ b/lib/l10n/app_localizations_it.dart
@@ -2042,4 +2042,118 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get createChannel => 'Crea Canale';
+
+ @override
+ String get wizardBack => 'Indietro';
+
+ @override
+ String get wizardSkip => 'Salta';
+
+ @override
+ String get wizardNext => 'Avanti';
+
+ @override
+ String get wizardGetStarted => 'Inizia';
+
+ @override
+ String get wizardWelcomeTitle => 'Benvenuto in MeshCore SAR';
+
+ @override
+ String get wizardWelcomeDescription =>
+ 'Un potente strumento di comunicazione offline per operazioni di ricerca e soccorso. Connettiti con il tuo team usando la tecnologia radio mesh quando le reti tradizionali non sono disponibili.';
+
+ @override
+ String get wizardConnectingTitle => 'Connessione alla Radio';
+
+ @override
+ String get wizardConnectingDescription =>
+ 'Collega il tuo smartphone a un dispositivo radio MeshCore tramite Bluetooth per iniziare a comunicare offline.';
+
+ @override
+ String get wizardConnectingFeature1 =>
+ 'Cerca dispositivi MeshCore nelle vicinanze';
+
+ @override
+ String get wizardConnectingFeature2 =>
+ 'Accoppia con la tua radio tramite Bluetooth';
+
+ @override
+ String get wizardConnectingFeature3 =>
+ 'Funziona completamente offline - non è richiesta connessione internet';
+
+ @override
+ String get wizardSimpleModeTitle => 'Modalità Semplice';
+
+ @override
+ String get wizardSimpleModeDescription =>
+ 'Nuovo alle reti mesh? Abilita la modalità semplice per un\'interfaccia semplificata con solo le funzioni essenziali.';
+
+ @override
+ String get wizardSimpleModeFeature1 =>
+ 'Interfaccia intuitiva per principianti con funzioni principali';
+
+ @override
+ String get wizardSimpleModeFeature2 =>
+ 'Passa alla modalità avanzata in qualsiasi momento dalle Impostazioni';
+
+ @override
+ String get wizardChannelTitle => 'Canali';
+
+ @override
+ String get wizardChannelDescription =>
+ 'Trasmetti messaggi a tutti su un canale, perfetto per annunci e coordinamento di tutto il team.';
+
+ @override
+ String get wizardChannelFeature1 =>
+ 'Canale pubblico per comunicazione generale del team';
+
+ @override
+ String get wizardChannelFeature2 =>
+ 'Crea canali personalizzati per gruppi specifici';
+
+ @override
+ String get wizardChannelFeature3 =>
+ 'I messaggi vengono automaticamente inoltrati attraverso la rete mesh';
+
+ @override
+ String get wizardContactsTitle => 'Contatti';
+
+ @override
+ String get wizardContactsDescription =>
+ 'I membri del tuo team appaiono automaticamente quando si uniscono alla rete mesh. Invia loro messaggi diretti o visualizza la loro posizione.';
+
+ @override
+ String get wizardContactsFeature1 => 'Contatti scoperti automaticamente';
+
+ @override
+ String get wizardContactsFeature2 => 'Invia messaggi diretti privati';
+
+ @override
+ String get wizardContactsFeature3 =>
+ 'Visualizza livello batteria e ultima volta visto';
+
+ @override
+ String get wizardMapTitle => 'Mappa & Posizione';
+
+ @override
+ String get wizardMapDescription =>
+ 'Traccia il tuo team in tempo reale e segna posizioni importanti per operazioni di ricerca e soccorso.';
+
+ @override
+ String get wizardMapFeature1 =>
+ 'Marcatori SAR per persone trovate, incendi e aree di staging';
+
+ @override
+ String get wizardMapFeature2 =>
+ 'Tracciamento GPS in tempo reale dei membri del team';
+
+ @override
+ String get wizardMapFeature3 => 'Scarica mappe offline per aree remote';
+
+ @override
+ String get wizardMapFeature4 =>
+ 'Disegna forme e condividi informazioni tattiche';
+
+ @override
+ String get viewWelcomeTutorial => 'Visualizza tutorial di benvenuto';
}
diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart
index 36e412b..29b98e4 100644
--- a/lib/l10n/app_localizations_sl.dart
+++ b/lib/l10n/app_localizations_sl.dart
@@ -2029,4 +2029,118 @@ class AppLocalizationsSl extends AppLocalizations {
@override
String get createChannel => 'Ustvari kanal';
+
+ @override
+ String get wizardBack => 'Nazaj';
+
+ @override
+ String get wizardSkip => 'Preskoči';
+
+ @override
+ String get wizardNext => 'Naprej';
+
+ @override
+ String get wizardGetStarted => 'Začni';
+
+ @override
+ String get wizardWelcomeTitle => 'Dobrodošli v MeshCore SAR';
+
+ @override
+ String get wizardWelcomeDescription =>
+ 'Močno orodje za komunikacijo brez omrežja za reševalne operacije. Povežite se s svojo ekipo z uporabo mrežne radijske tehnologije, ko tradicionalna omrežja niso na voljo.';
+
+ @override
+ String get wizardConnectingTitle => 'Povezava z Radijem';
+
+ @override
+ String get wizardConnectingDescription =>
+ 'Povežite svoj pametni telefon z napravo MeshCore radio preko Bluetootha za začetek komunikacije brez omrežja.';
+
+ @override
+ String get wizardConnectingFeature1 => 'Iskanje bližnjih naprav MeshCore';
+
+ @override
+ String get wizardConnectingFeature2 =>
+ 'Združite s svojim radijem preko Bluetootha';
+
+ @override
+ String get wizardConnectingFeature3 =>
+ 'Deluje popolnoma brez povezave - internet ni potreben';
+
+ @override
+ String get wizardSimpleModeTitle => 'Preprost Način';
+
+ @override
+ String get wizardSimpleModeDescription =>
+ 'Novi v mrežnem omrežju? Omogočite preprost način za poenostavljen vmesnik z le bistvenimi funkcijami.';
+
+ @override
+ String get wizardSimpleModeFeature1 =>
+ 'Vmesnik prijazen za začetnike z osnovnimi funkcijami';
+
+ @override
+ String get wizardSimpleModeFeature2 =>
+ 'Kadarkoli preklopite na napredni način v nastavitvah';
+
+ @override
+ String get wizardChannelTitle => 'Kanali';
+
+ @override
+ String get wizardChannelDescription =>
+ 'Oddajajte sporočila vsem na kanalu, popolno za objave in usklajevanje cele ekipe.';
+
+ @override
+ String get wizardChannelFeature1 =>
+ 'Javni kanal za splošno komunikacijo ekipe';
+
+ @override
+ String get wizardChannelFeature2 =>
+ 'Ustvarite kanale po meri za določene skupine';
+
+ @override
+ String get wizardChannelFeature3 =>
+ 'Sporočila so samodejno posredovana preko mreže';
+
+ @override
+ String get wizardContactsTitle => 'Stiki';
+
+ @override
+ String get wizardContactsDescription =>
+ 'Vaši člani ekipe se samodejno prikažejo, ko se pridružijo mrežnemu omrežju. Pošljite jim neposredna sporočila ali si oglejte njihovo lokacijo.';
+
+ @override
+ String get wizardContactsFeature1 => 'Stiki se odkrijejo samodejno';
+
+ @override
+ String get wizardContactsFeature2 =>
+ 'Pošiljajte zasebna neposredna sporočila';
+
+ @override
+ String get wizardContactsFeature3 =>
+ 'Oglejte si raven baterije in čas zadnjega ogleda';
+
+ @override
+ String get wizardMapTitle => 'Zemljevid & Lokacija';
+
+ @override
+ String get wizardMapDescription =>
+ 'Sledite svoji ekipi v realnem času in označite pomembne lokacije za reševalne operacije.';
+
+ @override
+ String get wizardMapFeature1 =>
+ 'SAR označevalci za najdene osebe, požare in območja postavitve';
+
+ @override
+ String get wizardMapFeature2 => 'Sledenje GPS članov ekipe v realnem času';
+
+ @override
+ String get wizardMapFeature3 =>
+ 'Prenesite zemljevide brez povezave za oddaljene kraje';
+
+ @override
+ String get wizardMapFeature4 =>
+ 'Narišite oblike in delite taktične informacije';
+
+ @override
+ String get viewWelcomeTutorial => 'Ogled vadnice dobrodošlice';
}
diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb
index 54a5647..95cec08 100644
--- a/lib/l10n/app_sl.arb
+++ b/lib/l10n/app_sl.arb
@@ -1029,5 +1029,38 @@
"channelCreatedSuccessfully": "Kanal uspešno ustvarjen",
"channelCreationFailed": "Neuspešno ustvarjanje kanala: {error}",
"allChannelSlotsInUse": "Vsa mesta za kanale so zasedena (maksimalno 39 prilagojenih kanalov)",
- "createChannel": "Ustvari kanal"
+ "createChannel": "Ustvari kanal",
+
+ "wizardBack": "Nazaj",
+ "wizardSkip": "Preskoči",
+ "wizardNext": "Naprej",
+ "wizardGetStarted": "Začni",
+ "wizardWelcomeTitle": "Dobrodošli v MeshCore SAR",
+ "wizardWelcomeDescription": "Močno orodje za komunikacijo brez omrežja za reševalne operacije. Povežite se s svojo ekipo z uporabo mrežne radijske tehnologije, ko tradicionalna omrežja niso na voljo.",
+ "wizardConnectingTitle": "Povezava z Radijem",
+ "wizardConnectingDescription": "Povežite svoj pametni telefon z napravo MeshCore radio preko Bluetootha za začetek komunikacije brez omrežja.",
+ "wizardConnectingFeature1": "Iskanje bližnjih naprav MeshCore",
+ "wizardConnectingFeature2": "Združite s svojim radijem preko Bluetootha",
+ "wizardConnectingFeature3": "Deluje popolnoma brez povezave - internet ni potreben",
+ "wizardSimpleModeTitle": "Preprost Način",
+ "wizardSimpleModeDescription": "Novi v mrežnem omrežju? Omogočite preprost način za poenostavljen vmesnik z le bistvenimi funkcijami.",
+ "wizardSimpleModeFeature1": "Vmesnik prijazen za začetnike z osnovnimi funkcijami",
+ "wizardSimpleModeFeature2": "Kadarkoli preklopite na napredni način v nastavitvah",
+ "wizardChannelTitle": "Kanali",
+ "wizardChannelDescription": "Oddajajte sporočila vsem na kanalu, popolno za objave in usklajevanje cele ekipe.",
+ "wizardChannelFeature1": "Javni kanal za splošno komunikacijo ekipe",
+ "wizardChannelFeature2": "Ustvarite kanale po meri za določene skupine",
+ "wizardChannelFeature3": "Sporočila so samodejno posredovana preko mreže",
+ "wizardContactsTitle": "Stiki",
+ "wizardContactsDescription": "Vaši člani ekipe se samodejno prikažejo, ko se pridružijo mrežnemu omrežju. Pošljite jim neposredna sporočila ali si oglejte njihovo lokacijo.",
+ "wizardContactsFeature1": "Stiki se odkrijejo samodejno",
+ "wizardContactsFeature2": "Pošiljajte zasebna neposredna sporočila",
+ "wizardContactsFeature3": "Oglejte si raven baterije in čas zadnjega ogleda",
+ "wizardMapTitle": "Zemljevid & Lokacija",
+ "wizardMapDescription": "Sledite svoji ekipi v realnem času in označite pomembne lokacije za reševalne operacije.",
+ "wizardMapFeature1": "SAR označevalci za najdene osebe, požare in območja postavitve",
+ "wizardMapFeature2": "Sledenje GPS članov ekipe v realnem času",
+ "wizardMapFeature3": "Prenesite zemljevide brez povezave za oddaljene kraje",
+ "wizardMapFeature4": "Narišite oblike in delite taktične informacije",
+ "viewWelcomeTutorial": "Ogled vadnice dobrodošlice"
}
diff --git a/lib/main.dart b/lib/main.dart
index bc32089..a9d3270 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -15,8 +15,10 @@ import 'services/tile_cache_service.dart';
import 'services/notification_service.dart';
import 'services/locale_preferences.dart';
import 'services/update_checker_service.dart';
+import 'services/wizard_preferences.dart';
import 'widgets/update_dialog.dart';
import 'screens/home_screen.dart';
+import 'screens/welcome_wizard_screen.dart';
import 'theme/app_theme.dart';
import 'l10n/app_localizations.dart';
@@ -36,6 +38,7 @@ class _MeshCoreSarAppState extends State {
Locale? _locale;
bool _isInitialized = false;
bool _shouldShowPermissionDialog = false;
+ bool _wizardCompleted = true; // Will be updated in _initializeApp()
@override
void initState() {
@@ -46,6 +49,10 @@ class _MeshCoreSarAppState extends State {
Future _initializeApp() async {
await _loadThemePreference();
await _loadLocalePreference();
+
+ // Check if welcome wizard has been completed
+ final wizardCompleted = await WizardPreferences.isWizardCompleted();
+
// Initialize notification service
await NotificationService().initialize();
@@ -57,6 +64,7 @@ class _MeshCoreSarAppState extends State {
_checkForUpdates();
setState(() {
+ _wizardCompleted = wizardCompleted;
_isInitialized = true;
});
}
@@ -102,6 +110,12 @@ class _MeshCoreSarAppState extends State {
});
}
+ void _handleWizardCompleted() {
+ setState(() {
+ _wizardCompleted = true;
+ });
+ }
+
/// Check for app updates on Android only
/// Shows dialog if update is available
Future _checkForUpdates() async {
@@ -224,13 +238,17 @@ class _MeshCoreSarAppState extends State {
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: LocalePreferences.supportedLocales,
- home: HomeScreen(
- onThemeChanged: _handleThemeChanged,
- onLocaleChanged: _handleLocaleChanged,
- currentTheme: _themeMode,
- currentLocale: _locale,
- shouldShowPermissionDialog: _shouldShowPermissionDialog,
- ),
+ home: _wizardCompleted
+ ? HomeScreen(
+ onThemeChanged: _handleThemeChanged,
+ onLocaleChanged: _handleLocaleChanged,
+ currentTheme: _themeMode,
+ currentLocale: _locale,
+ shouldShowPermissionDialog: _shouldShowPermissionDialog,
+ )
+ : WelcomeWizardScreen(
+ onCompleted: _handleWizardCompleted,
+ ),
);
},
);
diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart
index e5ff609..456c6c8 100644
--- a/lib/screens/settings_screen.dart
+++ b/lib/screens/settings_screen.dart
@@ -14,6 +14,7 @@ import '../utils/sample_data_generator.dart';
import '../theme/app_theme.dart';
import '../l10n/app_localizations.dart';
import 'sar_template_management_screen.dart';
+import 'welcome_wizard_screen.dart';
class SettingsScreen extends StatefulWidget {
final Function(AppThemeMode) onThemeChanged;
@@ -476,6 +477,25 @@ class _SettingsScreenState extends State {
);
},
),
+ ListTile(
+ leading: const Icon(Icons.school),
+ title: Text(AppLocalizations.of(context)!.viewWelcomeTutorial),
+ trailing: const Icon(Icons.chevron_right),
+ onTap: () async {
+ // Show wizard without resetting state - just as a modal
+ await Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => WelcomeWizardScreen(
+ onCompleted: () {
+ // Just pop back to settings when done
+ Navigator.of(context).pop();
+ },
+ ),
+ ),
+ );
+ },
+ ),
const Divider(),
// Permissions Section
diff --git a/lib/screens/welcome_wizard_screen.dart b/lib/screens/welcome_wizard_screen.dart
new file mode 100644
index 0000000..a61ea17
--- /dev/null
+++ b/lib/screens/welcome_wizard_screen.dart
@@ -0,0 +1,399 @@
+import 'package:flutter/material.dart';
+import '../l10n/app_localizations.dart';
+import '../services/wizard_preferences.dart';
+
+/// Welcome wizard screen to introduce new users to the app
+class WelcomeWizardScreen extends StatefulWidget {
+ final VoidCallback? onCompleted;
+
+ const WelcomeWizardScreen({super.key, this.onCompleted});
+
+ @override
+ State createState() => _WelcomeWizardScreenState();
+}
+
+class _WelcomeWizardScreenState extends State {
+ final PageController _pageController = PageController();
+ int _currentPage = 0;
+ static const int _totalPages = 6;
+
+ @override
+ void dispose() {
+ _pageController.dispose();
+ super.dispose();
+ }
+
+ void _onPageChanged(int page) {
+ setState(() {
+ _currentPage = page;
+ });
+ }
+
+ void _nextPage() {
+ if (_currentPage < _totalPages - 1) {
+ _pageController.nextPage(
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ );
+ } else {
+ _completeWizard();
+ }
+ }
+
+ void _previousPage() {
+ if (_currentPage > 0) {
+ _pageController.previousPage(
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ );
+ }
+ }
+
+ Future _completeWizard() async {
+ await WizardPreferences.setWizardCompleted(true);
+ if (mounted) {
+ widget.onCompleted?.call();
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final l10n = AppLocalizations.of(context)!;
+ final theme = Theme.of(context);
+ final colorScheme = theme.colorScheme;
+
+ return Scaffold(
+ body: SafeArea(
+ child: Column(
+ children: [
+ // Top bar with skip button
+ Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ if (_currentPage > 0)
+ TextButton.icon(
+ onPressed: _previousPage,
+ icon: const Icon(Icons.arrow_back),
+ label: Text(l10n.wizardBack),
+ )
+ else
+ const SizedBox(width: 80),
+ if (_currentPage < _totalPages - 1)
+ TextButton(
+ onPressed: _completeWizard,
+ child: Text(l10n.wizardSkip),
+ )
+ else
+ const SizedBox(width: 80),
+ ],
+ ),
+ ),
+
+ // Page view with wizard content
+ Expanded(
+ child: PageView(
+ controller: _pageController,
+ onPageChanged: _onPageChanged,
+ children: [
+ _buildWelcomePage(context, l10n, colorScheme),
+ _buildConnectingPage(context, l10n, colorScheme),
+ _buildSimpleModePage(context, l10n, colorScheme),
+ _buildChannelPage(context, l10n, colorScheme),
+ _buildContactsPage(context, l10n, colorScheme),
+ _buildMapPage(context, l10n, colorScheme),
+ ],
+ ),
+ ),
+
+ // Page indicators
+ Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: List.generate(
+ _totalPages,
+ (index) => Container(
+ margin: const EdgeInsets.symmetric(horizontal: 4.0),
+ width: _currentPage == index ? 12.0 : 8.0,
+ height: _currentPage == index ? 12.0 : 8.0,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ color: _currentPage == index
+ ? colorScheme.primary
+ : colorScheme.outline.withValues(alpha: 0.3),
+ ),
+ ),
+ ),
+ ),
+ ),
+
+ // Next/Get Started button
+ Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: SizedBox(
+ width: double.infinity,
+ child: ElevatedButton(
+ onPressed: _nextPage,
+ style: ElevatedButton.styleFrom(
+ padding: const EdgeInsets.symmetric(vertical: 16.0),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(12),
+ ),
+ ),
+ child: Text(
+ _currentPage < _totalPages - 1
+ ? l10n.wizardNext
+ : l10n.wizardGetStarted,
+ style: const TextStyle(fontSize: 16),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ Widget _buildWelcomePage(
+ BuildContext context,
+ AppLocalizations l10n,
+ ColorScheme colorScheme,
+ ) {
+ return _buildPage(
+ icon: Icons.waving_hand,
+ iconColor: Colors.orange,
+ title: l10n.wizardWelcomeTitle,
+ description: l10n.wizardWelcomeDescription,
+ colorScheme: colorScheme,
+ );
+ }
+
+ Widget _buildConnectingPage(
+ BuildContext context,
+ AppLocalizations l10n,
+ ColorScheme colorScheme,
+ ) {
+ return _buildPage(
+ icon: Icons.bluetooth_searching,
+ iconColor: Colors.blue,
+ title: l10n.wizardConnectingTitle,
+ description: l10n.wizardConnectingDescription,
+ features: [
+ _FeatureItem(
+ icon: Icons.radio,
+ text: l10n.wizardConnectingFeature1,
+ ),
+ _FeatureItem(
+ icon: Icons.link,
+ text: l10n.wizardConnectingFeature2,
+ ),
+ _FeatureItem(
+ icon: Icons.wifi_off,
+ text: l10n.wizardConnectingFeature3,
+ ),
+ ],
+ colorScheme: colorScheme,
+ );
+ }
+
+ Widget _buildSimpleModePage(
+ BuildContext context,
+ AppLocalizations l10n,
+ ColorScheme colorScheme,
+ ) {
+ return _buildPage(
+ icon: Icons.toggle_on,
+ iconColor: Colors.green,
+ title: l10n.wizardSimpleModeTitle,
+ description: l10n.wizardSimpleModeDescription,
+ features: [
+ _FeatureItem(
+ icon: Icons.check_circle_outline,
+ text: l10n.wizardSimpleModeFeature1,
+ ),
+ _FeatureItem(
+ icon: Icons.settings,
+ text: l10n.wizardSimpleModeFeature2,
+ ),
+ ],
+ colorScheme: colorScheme,
+ );
+ }
+
+ Widget _buildChannelPage(
+ BuildContext context,
+ AppLocalizations l10n,
+ ColorScheme colorScheme,
+ ) {
+ return _buildPage(
+ icon: Icons.campaign,
+ iconColor: Colors.purple,
+ title: l10n.wizardChannelTitle,
+ description: l10n.wizardChannelDescription,
+ features: [
+ _FeatureItem(
+ icon: Icons.public,
+ text: l10n.wizardChannelFeature1,
+ ),
+ _FeatureItem(
+ icon: Icons.groups,
+ text: l10n.wizardChannelFeature2,
+ ),
+ _FeatureItem(
+ icon: Icons.send,
+ text: l10n.wizardChannelFeature3,
+ ),
+ ],
+ colorScheme: colorScheme,
+ );
+ }
+
+ Widget _buildContactsPage(
+ BuildContext context,
+ AppLocalizations l10n,
+ ColorScheme colorScheme,
+ ) {
+ return _buildPage(
+ icon: Icons.people,
+ iconColor: Colors.teal,
+ title: l10n.wizardContactsTitle,
+ description: l10n.wizardContactsDescription,
+ features: [
+ _FeatureItem(
+ icon: Icons.person_add,
+ text: l10n.wizardContactsFeature1,
+ ),
+ _FeatureItem(
+ icon: Icons.chat,
+ text: l10n.wizardContactsFeature2,
+ ),
+ _FeatureItem(
+ icon: Icons.battery_std,
+ text: l10n.wizardContactsFeature3,
+ ),
+ ],
+ colorScheme: colorScheme,
+ );
+ }
+
+ Widget _buildMapPage(
+ BuildContext context,
+ AppLocalizations l10n,
+ ColorScheme colorScheme,
+ ) {
+ return _buildPage(
+ icon: Icons.map,
+ iconColor: Colors.red,
+ title: l10n.wizardMapTitle,
+ description: l10n.wizardMapDescription,
+ features: [
+ _FeatureItem(
+ icon: Icons.location_on,
+ text: l10n.wizardMapFeature1,
+ ),
+ _FeatureItem(
+ icon: Icons.person_pin_circle,
+ text: l10n.wizardMapFeature2,
+ ),
+ _FeatureItem(
+ icon: Icons.offline_pin,
+ text: l10n.wizardMapFeature3,
+ ),
+ _FeatureItem(
+ icon: Icons.draw,
+ text: l10n.wizardMapFeature4,
+ ),
+ ],
+ colorScheme: colorScheme,
+ );
+ }
+
+ Widget _buildPage({
+ required IconData icon,
+ required Color iconColor,
+ required String title,
+ required String description,
+ List<_FeatureItem>? features,
+ required ColorScheme colorScheme,
+ }) {
+ return SingleChildScrollView(
+ padding: const EdgeInsets.all(24.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const SizedBox(height: 20),
+ // Icon
+ Container(
+ padding: const EdgeInsets.all(24.0),
+ decoration: BoxDecoration(
+ color: iconColor.withValues(alpha: 0.1),
+ shape: BoxShape.circle,
+ ),
+ child: Icon(
+ icon,
+ size: 80,
+ color: iconColor,
+ ),
+ ),
+ const SizedBox(height: 32),
+ // Title
+ Text(
+ title,
+ style: Theme.of(context).textTheme.headlineMedium?.copyWith(
+ fontWeight: FontWeight.bold,
+ color: colorScheme.onSurface,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(height: 16),
+ // Description
+ Text(
+ description,
+ style: Theme.of(context).textTheme.bodyLarge?.copyWith(
+ color: colorScheme.onSurface.withValues(alpha: 0.7),
+ height: 1.5,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ if (features != null && features.isNotEmpty) ...[
+ const SizedBox(height: 32),
+ // Features list
+ ...features.map((feature) => Padding(
+ padding: const EdgeInsets.symmetric(vertical: 8.0),
+ child: Row(
+ children: [
+ Icon(
+ feature.icon,
+ color: colorScheme.primary,
+ size: 24,
+ ),
+ const SizedBox(width: 16),
+ Expanded(
+ child: Text(
+ feature.text,
+ style:
+ Theme.of(context).textTheme.bodyMedium?.copyWith(
+ color: colorScheme.onSurface,
+ ),
+ ),
+ ),
+ ],
+ ),
+ )),
+ ],
+ const SizedBox(height: 20),
+ ],
+ ),
+ );
+ }
+}
+
+class _FeatureItem {
+ final IconData icon;
+ final String text;
+
+ _FeatureItem({required this.icon, required this.text});
+}
diff --git a/lib/services/wizard_preferences.dart b/lib/services/wizard_preferences.dart
new file mode 100644
index 0000000..a5e1825
--- /dev/null
+++ b/lib/services/wizard_preferences.dart
@@ -0,0 +1,42 @@
+import 'package:shared_preferences/shared_preferences.dart';
+
+/// Service to manage welcome wizard preferences and state
+class WizardPreferences {
+ static const String _wizardCompletedKey = 'wizard_completed';
+ static const String _wizardVersionKey = 'wizard_version';
+ static const int _currentWizardVersion = 1;
+
+ /// Check if the welcome wizard has been completed
+ static Future isWizardCompleted() async {
+ final prefs = await SharedPreferences.getInstance();
+ final completed = prefs.getBool(_wizardCompletedKey) ?? false;
+ final version = prefs.getInt(_wizardVersionKey) ?? 0;
+
+ // Re-show wizard if version has changed (for major updates)
+ return completed && version >= _currentWizardVersion;
+ }
+
+ /// Mark the welcome wizard as completed
+ static Future setWizardCompleted(bool completed) async {
+ final prefs = await SharedPreferences.getInstance();
+ await prefs.setBool(_wizardCompletedKey, completed);
+
+ if (completed) {
+ // Store current version when wizard is completed
+ await prefs.setInt(_wizardVersionKey, _currentWizardVersion);
+ }
+ }
+
+ /// Get the wizard version last shown to the user
+ static Future getWizardVersion() async {
+ final prefs = await SharedPreferences.getInstance();
+ return prefs.getInt(_wizardVersionKey) ?? 0;
+ }
+
+ /// Reset wizard state (useful for testing or re-showing tutorial)
+ static Future resetWizard() async {
+ final prefs = await SharedPreferences.getInstance();
+ await prefs.setBool(_wizardCompletedKey, false);
+ await prefs.setInt(_wizardVersionKey, 0);
+ }
+}