feat: Add welcome wizard for new users

- Implemented a multi-page welcome wizard to introduce new users to the app's features.
- Added localization support for the wizard in English, Spanish, French, Croatian, Italian, and Slovenian.
- Integrated wizard completion state management using SharedPreferences.
- Updated main app flow to show the wizard if it hasn't been completed.
- Added a settings option to view the welcome tutorial again.
This commit is contained in:
Janez T
2025-10-28 11:20:30 +01:00
parent 1249f39ac2
commit 5d943ff1a4
20 changed files with 1856 additions and 19 deletions

View File

@@ -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 \`
<div class="commit-item">
<div class="commit-header">
<span class="commit-hash">\${commit.hash}</span>
<span class="commit-date">\${dateStr}</span>
<span class="commit-hash">\${escapeHtml(commit.hash)}</span>
<span class="commit-date">\${escapeHtml(dateStr)}</span>
</div>
<div class="commit-message">\${commit.message}</div>
<div class="commit-author">by \${commit.author}</div>
<div class="commit-message">\${escapeHtml(commit.message)}</div>
<div class="commit-author">by \${escapeHtml(commit.author)}</div>
</div>
\`;
}).join('');

View File

@@ -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"
}

View File

@@ -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"
}
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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

View File

@@ -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';
}

View File

@@ -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';
}

View File

@@ -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';
}

View File

@@ -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';
}

View File

@@ -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';
}

View File

@@ -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';
}

View File

@@ -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';
}

View File

@@ -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"
}

View File

@@ -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<MeshCoreSarApp> {
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<MeshCoreSarApp> {
Future<void> _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<MeshCoreSarApp> {
_checkForUpdates();
setState(() {
_wizardCompleted = wizardCompleted;
_isInitialized = true;
});
}
@@ -102,6 +110,12 @@ class _MeshCoreSarAppState extends State<MeshCoreSarApp> {
});
}
void _handleWizardCompleted() {
setState(() {
_wizardCompleted = true;
});
}
/// Check for app updates on Android only
/// Shows dialog if update is available
Future<void> _checkForUpdates() async {
@@ -224,13 +238,17 @@ class _MeshCoreSarAppState extends State<MeshCoreSarApp> {
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,
),
);
},
);

View File

@@ -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<SettingsScreen> {
);
},
),
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

View File

@@ -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<WelcomeWizardScreen> createState() => _WelcomeWizardScreenState();
}
class _WelcomeWizardScreenState extends State<WelcomeWizardScreen> {
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<void> _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});
}

View File

@@ -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<bool> 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<void> 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<int> getWizardVersion() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getInt(_wizardVersionKey) ?? 0;
}
/// Reset wizard state (useful for testing or re-showing tutorial)
static Future<void> resetWizard() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_wizardCompletedKey, false);
await prefs.setInt(_wizardVersionKey, 0);
}
}