mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Additional onboarding cleanup
This commit is contained in:
parent
f7531f5b9a
commit
f58b8376e6
8 changed files with 567 additions and 189 deletions
|
|
@ -2,7 +2,6 @@
|
|||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"" : {
|
||||
"shouldTranslate" : false,
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -10,7 +9,8 @@
|
|||
"value" : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"\t%@" : {
|
||||
"localizations" : {
|
||||
|
|
@ -225,100 +225,104 @@
|
|||
},
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
" : %@" : {
|
||||
": %@" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %@"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %@"
|
||||
"value" : ": %@"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %@"
|
||||
"value" : ": %@"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %@"
|
||||
"value" : ": %@"
|
||||
}
|
||||
},
|
||||
"sr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %@"
|
||||
"value" : ": %@"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %@"
|
||||
"value" : ": %@"
|
||||
}
|
||||
},
|
||||
"zh-Hant-TW" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %@"
|
||||
"value" : ": %@"
|
||||
}
|
||||
}
|
||||
},
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
" : %d" : {
|
||||
": %d" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %d"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %d"
|
||||
"value" : ": %d"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %d"
|
||||
"value" : ": %d"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %d"
|
||||
"value" : ": %d"
|
||||
}
|
||||
},
|
||||
"sr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %d"
|
||||
"value" : ": %d"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %d"
|
||||
"value" : ": %d"
|
||||
}
|
||||
},
|
||||
"zh-Hant-TW" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : " : %d"
|
||||
"value" : ": %d"
|
||||
}
|
||||
}
|
||||
},
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"\"Disconnect Meshtastic\" — disconnect from the connected BLE node." : {
|
||||
"comment" : "A description of how to use the \"Disconnect Node\" Siri shortcut.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"\"Send a Meshtastic direct message\" — send a private message to a node." : {
|
||||
"comment" : "A description of how to send a direct message to a node using Siri.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"\"Send a Meshtastic group message\" — send a message to a mesh channel." : {
|
||||
"comment" : "A description of how to send a group message using Siri.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"\"Shut down my Meshtastic node\" or \"Restart my Meshtastic node\"." : {
|
||||
"comment" : "A description of how to use Siri to restart or shut down a node.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"(Re)define PIN_GPS_EN for your board." : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -2352,6 +2356,7 @@
|
|||
}
|
||||
},
|
||||
"🦕 End of life Version 🦖 ☄️" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -3018,7 +3023,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"A default self-signed certificate is included for localhost connections. Import a custom .p12 if needed. Client CA (.pem) validates connecting TAK clients." : {},
|
||||
"A default self-signed certificate is included for localhost connections. Import a custom .p12 if needed. Client CA (.pem) validates connecting TAK clients." : {
|
||||
|
||||
},
|
||||
"A green lock means the channel is securely encrypted with either a 128 or 256 bit AES key." : {
|
||||
"localizations" : {
|
||||
"es" : {
|
||||
|
|
@ -3863,7 +3870,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Add CA" : {},
|
||||
"Add CA" : {
|
||||
|
||||
},
|
||||
"Add Channel" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -4083,6 +4092,7 @@
|
|||
}
|
||||
},
|
||||
"Additional help" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -4134,6 +4144,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Additional Help" : {
|
||||
"comment" : "A button that opens a link to the Meshtastic FAQ.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Address" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -7008,6 +7022,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Background Activity" : {
|
||||
"comment" : "A title for a screen that describes the benefits of enabling background location tracking.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Background Mesh Tracking" : {
|
||||
"comment" : "A description of the background mesh tracking feature.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Backup" : {
|
||||
"localizations" : {
|
||||
"ja" : {
|
||||
|
|
@ -7717,6 +7739,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Battery Usage" : {
|
||||
"comment" : "A description of the battery usage of enabling background activity.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Baud" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -9471,6 +9497,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"CarPlay Messaging" : {
|
||||
"comment" : "A description of how to send a message to a mesh channel using CarPlay.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Categories" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -11484,8 +11514,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Client CA Certificate" : {},
|
||||
"Client Configuration" : {},
|
||||
"Client CA Certificate" : {
|
||||
|
||||
},
|
||||
"Client Configuration" : {
|
||||
|
||||
},
|
||||
"Client Hidden" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
|
|
@ -12186,7 +12220,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Configuration" : {},
|
||||
"Configuration" : {
|
||||
|
||||
},
|
||||
"Configuration for: %@" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -12447,6 +12483,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Configure Siri & Shortcuts" : {
|
||||
"comment" : "A button that will open the app's settings to configure Siri and Shortcuts.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Confirm" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -12653,6 +12693,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Connect to nodes on your local Wi-Fi network." : {
|
||||
"comment" : "A description of how to connect to nodes on your local Wi-Fi network.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Connect to your Meshtastic node via Bluetooth Low Energy for the best messaging experience." : {
|
||||
"comment" : "A description of the Bluetooth connectivity feature.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Connected" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -12735,6 +12783,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Connected firmware: **%@**" : {
|
||||
"comment" : "A label displaying the firmware version of a device. The argument is the firmware version.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Connected Node %@" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -13221,6 +13273,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Continue" : {
|
||||
"comment" : "A button that will continue to the next step in the onboarding process.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Continuous Location Updates" : {
|
||||
"comment" : "A description of the continuous location updates feature.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Control Type" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -13990,6 +14050,7 @@
|
|||
}
|
||||
},
|
||||
"Current Firmware Version: %@, Latest Firmware Version: %@" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -14047,6 +14108,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Current Firmware Version: %@, Minimum Required Version: %@" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
"value" : "Current Firmware Version: %1$@, Minimum Required Version: %2$@"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Current: %lld" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -14570,7 +14641,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Delete All" : {},
|
||||
"Delete All" : {
|
||||
|
||||
},
|
||||
"Delete all config, keys and BLE bonds? " : {
|
||||
"localizations" : {
|
||||
"es" : {
|
||||
|
|
@ -18174,7 +18247,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Download TAK Server Data Package" : {},
|
||||
"Download TAK Server Data Package" : {
|
||||
|
||||
},
|
||||
"Drag & Drop Firmware Update" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -18819,6 +18894,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Enable Background Activity" : {
|
||||
"comment" : "A toggle to enable or disable background activity.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Enable broadcasting device metrics to the mesh network. When disabled, metrics are only sent to connected clients." : {
|
||||
"localizations" : {
|
||||
"es" : {
|
||||
|
|
@ -18961,7 +19040,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Enable TAK Server" : {},
|
||||
"Enable TAK Server" : {
|
||||
|
||||
},
|
||||
"Enable this device as a Store and Forward server. Requires an ESP32 device with PSRAM." : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -19351,6 +19432,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Enabling background activity may increase battery usage. You can toggle this at any time in the app settings." : {
|
||||
"comment" : "A description of the battery usage of enabling background activity.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Enabling Ethernet will disable the bluetooth connection to the app." : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -19728,8 +19813,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Enter P12 Password" : {},
|
||||
"Enter the password for the PKCS#12 file" : {},
|
||||
"Enter P12 Password" : {
|
||||
|
||||
},
|
||||
"Enter the password for the PKCS#12 file" : {
|
||||
|
||||
},
|
||||
"environment" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
|
|
@ -22118,6 +22207,7 @@
|
|||
}
|
||||
},
|
||||
"Firmware update docs" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -22169,6 +22259,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Firmware Update Docs" : {
|
||||
"comment" : "A link to the firmware update documentation.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Firmware Update Required" : {
|
||||
"comment" : "A title for a screen that displays a firmware update is required message.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Firmware Updates" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -23771,7 +23869,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Generate a data package (.zip) to configure TAK clients to connect to this server." : {},
|
||||
"Generate a data package (.zip) to configure TAK clients to connect to this server." : {
|
||||
|
||||
},
|
||||
"Generate a new private key to replace the one currently in use. The public key will automatically be regenerated from your private key." : {
|
||||
"localizations" : {
|
||||
"es" : {
|
||||
|
|
@ -26181,6 +26281,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"How to Update" : {
|
||||
"comment" : "A label displayed above the list of available firmware update options.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"How to update Firmware" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -27266,10 +27370,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Import" : {},
|
||||
"Import .pem" : {},
|
||||
"Import Custom .p12" : {},
|
||||
"Import Error" : {},
|
||||
"Import" : {
|
||||
|
||||
},
|
||||
"Import .pem" : {
|
||||
|
||||
},
|
||||
"Import Custom .p12" : {
|
||||
|
||||
},
|
||||
"Import Error" : {
|
||||
|
||||
},
|
||||
"Import Route" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -28066,6 +28178,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Keep the mesh map updated and send your position to the mesh even while using other apps." : {
|
||||
"comment" : "A description of the benefits of continuous location updates.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Key" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -31354,7 +31470,12 @@
|
|||
"comment" : "A description of the read-only mode feature in TAK Server.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Meshtastic does not collect any personal information. We do anonymously collect usage and crash data to improve the app." : {
|
||||
"comment" : "A description of how user data is used by Meshtastic.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Meshtastic does not collect any personal information. We do anonymously collect usage and crash data to improve the app. You can opt out under app settings." : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -31682,6 +31803,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Message Notifications" : {
|
||||
"comment" : "A description of the message notifications feature.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Message received from the text message app." : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
|
|
@ -32201,6 +32326,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Minimum required: **%@**" : {
|
||||
"comment" : "A label displaying the minimum required firmware version.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Minimum time between detection broadcasts" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
|
|
@ -32997,7 +33126,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"mTLS" : {},
|
||||
"mTLS" : {
|
||||
|
||||
},
|
||||
"Multiplier" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -36935,6 +37066,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Open Web Flasher" : {
|
||||
"comment" : "A button that opens the Web Flasher app.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Optimized for 2 color displays" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
|
|
@ -39159,7 +39294,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Port" : {},
|
||||
"Port" : {
|
||||
|
||||
},
|
||||
"Position" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -41905,6 +42042,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Read and reply to Meshtastic channel and direct messages directly from your car's display using CarPlay." : {
|
||||
"comment" : "A description of how to use CarPlay with Meshtastic.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Read-Only Mode" : {
|
||||
"comment" : "A toggle that allows the user to enable or disable read-only mode for the TAK server.",
|
||||
"isCommentAutoGenerated" : true
|
||||
|
|
@ -42212,6 +42353,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Receive notifications for incoming messages and critical alerts even when the app is in the background." : {
|
||||
"comment" : "A description of the notification feature.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Receive position updates from other nodes and maintain an accurate picture of the mesh while in the background." : {
|
||||
"comment" : "A description of the benefits of enabling background mesh tracking.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Received a negative acknowledgment" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
|
|
@ -42481,6 +42630,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Recommended secure version: **%@**" : {
|
||||
"comment" : "A label displaying the recommended secure version of the connected device.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Recording route" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -42816,7 +42969,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Reload Bundled Certificates" : {},
|
||||
"Reload Bundled Certificates" : {
|
||||
|
||||
},
|
||||
"Remote administration for: %@" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -43623,7 +43778,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Reset to Default" : {},
|
||||
"Reset to Default" : {
|
||||
|
||||
},
|
||||
"Restart" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -43676,7 +43833,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Restart Server" : {},
|
||||
"Restart Server" : {
|
||||
|
||||
},
|
||||
"Restart to the node you are connected to" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -46448,8 +46607,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Secure mTLS connection on port 8089. Both server and client certificates are required." : {},
|
||||
|
||||
"Secure mTLS connection on port 8089. Both server and client certificates are required. TAK Channel Index selects the channel index where TAK messages will be sent." : {
|
||||
"comment" : "A footer for the TAK Server configuration section.",
|
||||
"isCommentAutoGenerated" : true
|
||||
|
|
@ -46512,6 +46669,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Security Advisory" : {
|
||||
"comment" : "A title for a security advisory displayed in a card.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Security Config" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -46628,6 +46789,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Security Update Recommended" : {
|
||||
"comment" : "A title for a view that warns the user that their device is running an outdated firmware version.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Select" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
|
|
@ -47581,6 +47746,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Send and receive Meshtastic messages hands-free using Siri and CarPlay." : {
|
||||
"comment" : "A description of how to use Siri and CarPlay with Meshtastic.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Send ASCII bell with alert message. Useful for triggering external notification on bell." : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -49143,7 +49312,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Server Certificate" : {},
|
||||
"Server Certificate" : {
|
||||
|
||||
},
|
||||
"Server Option" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -49190,7 +49361,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Server Status" : {},
|
||||
"Server Status" : {
|
||||
|
||||
},
|
||||
"Set" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -49237,6 +49410,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Set a channel name" : {
|
||||
"comment" : "A label for a button that sets a channel name.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Set LoRa Region" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -49856,6 +50033,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Share with TAK Buddies" : {
|
||||
"comment" : "A button that shares the QR code with TAK buddies.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Share your location in real-time and keep your group coordinated with integrated GPS features." : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
|
|
@ -50614,6 +50795,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Shut Down / Restart Node" : {
|
||||
"comment" : "A Siri shortcut to restart or shut down a node.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Shut Down Node?" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -50970,6 +51155,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Siri & CarPlay" : {
|
||||
"comment" : "A description of how to use Siri and CarPlay with Meshtastic.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Siri, Shortcuts & CarPlay" : {
|
||||
"comment" : "A label displayed above the Siri, Shortcuts & CarPlay onboarding view.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Six Hours" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
|
|
@ -52018,7 +52211,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Status" : {},
|
||||
"Status" : {
|
||||
|
||||
},
|
||||
"Stay Connected Anywhere" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
|
|
@ -52656,9 +52851,18 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"TAK Cannot Be Used on Public Channel" : {
|
||||
"comment" : "A warning displayed when the user's primary channel is public.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"TAK Channel Index" : {
|
||||
"comment" : "A label for the TAK channel index.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"TAK Server" : {
|
||||
|
||||
},
|
||||
"TAK Server" : {},
|
||||
"TAK Tracker" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
|
|
@ -53942,7 +54146,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"The Meshtastic Apple app requires firmware version %@ or later. Older firmware versions are no longer supported and may have compatibility issues or missing features." : {
|
||||
"comment" : "A body text that explains that the app requires a certain version of the firmware.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"The Meshtastic Apple apps support firmware version %@ and above." : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -55989,7 +56198,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"TLS Certificates" : {},
|
||||
"TLS Certificates" : {
|
||||
|
||||
},
|
||||
"TLS Enabled" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -60062,6 +60273,7 @@
|
|||
}
|
||||
},
|
||||
"Version %@ includes substantial network optimizations and extensive changes to devices and client apps. Only nodes version %@ and above are supported." : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -61187,6 +61399,7 @@
|
|||
}
|
||||
},
|
||||
"Welcome to" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -61214,6 +61427,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Welcome to Meshtastic" : {
|
||||
"comment" : "The title of the onboarding screen.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"What does the lock mean?" : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -62416,6 +62633,10 @@
|
|||
"comment" : "A message displayed when a user successfully configures their primary channel for TAK. It instructs the user to share the QR code to invite TAK buddies.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Your connected device is running firmware older than **%@**, which contains known security vulnerabilities. Updating your firmware is strongly recommended to protect your device and mesh network." : {
|
||||
"comment" : "A body text that describes the security advisory.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Your current location will be set as the fixed position and broadcast over the mesh on the position interval." : {
|
||||
"localizations" : {
|
||||
"da" : {
|
||||
|
|
@ -62889,88 +63110,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
": %@" : {
|
||||
"localizations" : {
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %@"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %@"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %@"
|
||||
}
|
||||
},
|
||||
"sr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %@"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %@"
|
||||
}
|
||||
},
|
||||
"zh-Hant-TW" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %@"
|
||||
}
|
||||
}
|
||||
},
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
": %d" : {
|
||||
"localizations" : {
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %d"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %d"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %d"
|
||||
}
|
||||
},
|
||||
"sr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %d"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %d"
|
||||
}
|
||||
},
|
||||
"zh-Hant-TW" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ": %d"
|
||||
}
|
||||
}
|
||||
},
|
||||
"shouldTranslate" : false
|
||||
}
|
||||
},
|
||||
"version" : "1.1"
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@
|
|||
25F5D5C22C3F6E4B008036E3 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F5D5C12C3F6E4B008036E3 /* AppState.swift */; };
|
||||
25F5D5D12C4375DF008036E3 /* RouterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F5D5D02C4375DF008036E3 /* RouterTests.swift */; };
|
||||
AA0001012E2730EC00600001 /* ConnectViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA00010022E2730EC0060000 /* ConnectViewTests.swift */; };
|
||||
DD9C70102E9F2A0000029299 /* DeviceOnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9C70112E9F2A0000029299 /* DeviceOnboardingTests.swift */; };
|
||||
2849A5E4CE9FDC1DB33DFA34 /* TAKConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01028778B8BFD81F7A039593 /* TAKConnection.swift */; };
|
||||
300424F80C4A445A0FBAE82D /* TAKMeshtasticBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D006C85B250291D5925F30 /* TAKMeshtasticBridge.swift */; };
|
||||
3D3417B42E2730EC006A988B /* GeoJSONOverlayManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D3417B32E2730EC006A988B /* GeoJSONOverlayManager.swift */; };
|
||||
|
|
@ -204,6 +205,7 @@
|
|||
DD798B072915928D005217CD /* ChannelMessageList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD798B062915928D005217CD /* ChannelMessageList.swift */; };
|
||||
DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169FE272476C700F4AB02 /* LogDocument.swift */; };
|
||||
DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD836AE626F6B38600ABCC23 /* Connect.swift */; };
|
||||
DD4756AB2E9F1A0000029299 /* SecurityVersionNag.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4756AA2E9F1A0000029299 /* SecurityVersionNag.swift */; };
|
||||
DD86D40A287F04F100BAEB7A /* InvalidVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD86D409287F04F100BAEB7A /* InvalidVersion.swift */; };
|
||||
DD86D40C287F401000BAEB7A /* SaveChannelQRCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD86D40B287F401000BAEB7A /* SaveChannelQRCode.swift */; };
|
||||
DD86D40F2881BE4C00BAEB7A /* CsvDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD86D40E2881BE4C00BAEB7A /* CsvDocument.swift */; };
|
||||
|
|
@ -413,6 +415,7 @@
|
|||
25F5D5C72C4375A8008036E3 /* MeshtasticTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeshtasticTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
25F5D5D02C4375DF008036E3 /* RouterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterTests.swift; sourceTree = "<group>"; };
|
||||
AA00010022E2730EC0060000 /* ConnectViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectViewTests.swift; sourceTree = "<group>"; };
|
||||
DD9C70112E9F2A0000029299 /* DeviceOnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceOnboardingTests.swift; sourceTree = "<group>"; };
|
||||
2B37CCEE8B44A4BA123ED118 /* TAKServerManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TAKServerManager.swift; sourceTree = "<group>"; };
|
||||
3D0A8ABAEF1E587683970927 /* EXICodec.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EXICodec.swift; sourceTree = "<group>"; };
|
||||
3D3417B32E2730EC006A988B /* GeoJSONOverlayManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoJSONOverlayManager.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -565,6 +568,7 @@
|
|||
DD7E235F2C7AA3E50078ACDF /* MeshtasticDataModelV 43.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 43.xcdatamodel"; sourceTree = "<group>"; };
|
||||
DD8169FE272476C700F4AB02 /* LogDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogDocument.swift; sourceTree = "<group>"; };
|
||||
DD836AE626F6B38600ABCC23 /* Connect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Connect.swift; sourceTree = "<group>"; };
|
||||
DD4756AA2E9F1A0000029299 /* SecurityVersionNag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityVersionNag.swift; sourceTree = "<group>"; };
|
||||
DD86D409287F04F100BAEB7A /* InvalidVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvalidVersion.swift; sourceTree = "<group>"; };
|
||||
DD86D40B287F401000BAEB7A /* SaveChannelQRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveChannelQRCode.swift; sourceTree = "<group>"; };
|
||||
DD86D40E2881BE4C00BAEB7A /* CsvDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CsvDocument.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -903,6 +907,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
AA00010022E2730EC0060000 /* ConnectViewTests.swift */,
|
||||
DD9C70112E9F2A0000029299 /* DeviceOnboardingTests.swift */,
|
||||
25F5D5D02C4375DF008036E3 /* RouterTests.swift */,
|
||||
);
|
||||
path = MeshtasticTests;
|
||||
|
|
@ -1002,7 +1007,8 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
DD836AE626F6B38600ABCC23 /* Connect.swift */,
|
||||
DD86D409287F04F100BAEB7A /* InvalidVersion.swift */,
|
||||
DD4756AA2E9F1A0000029299 /* SecurityVersionNag.swift */,
|
||||
DD86D409287F04F100BAEB7A /* InvalidVersion.swift */
|
||||
);
|
||||
path = Connect;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1661,6 +1667,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
AA0001012E2730EC00600001 /* ConnectViewTests.swift in Sources */,
|
||||
DD9C70102E9F2A0000029299 /* DeviceOnboardingTests.swift in Sources */,
|
||||
25F5D5D12C4375DF008036E3 /* RouterTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -1684,6 +1691,7 @@
|
|||
DDA9515C2BC6631200CEA535 /* TelemetryEnums.swift in Sources */,
|
||||
DDFEB3BB29900C1200EE7472 /* CurrentConditionsCompact.swift in Sources */,
|
||||
DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */,
|
||||
DD4756AB2E9F1A0000029299 /* SecurityVersionNag.swift in Sources */,
|
||||
D93069082B81DF040066FBC8 /* SaveConfigButton.swift in Sources */,
|
||||
DD5E523F298F5A9E00D21B61 /* AirQualityIndex.swift in Sources */,
|
||||
DDD5BB182C2F9C36007E03CA /* OSLogEntryLog.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -46,6 +46,26 @@ extension View {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Standard capsule-shaped prominent button styling.
|
||||
/// On iOS 26+ the button also receives a glass background effect.
|
||||
@ViewBuilder
|
||||
func capsuleButtonStyle() -> some View {
|
||||
if #available(iOS 26.0, macOS 26.0, *) {
|
||||
self
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.buttonStyle(.borderedProminent)
|
||||
.glassEffect(in: .capsule)
|
||||
} else {
|
||||
self
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.buttonStyle(.borderedProminent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct FirstAppear: ViewModifier {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
</array>
|
||||
<key>com.apple.developer.carplay-communication</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.siri</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.usernotifications.critical-alerts</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.weatherkit</key>
|
||||
|
|
|
|||
|
|
@ -581,18 +581,18 @@ struct DeviceConnectRow: View {
|
|||
}
|
||||
// Show transport type
|
||||
#if !targetEnvironment(macCatalyst)
|
||||
HStack(alignment: .center){
|
||||
HStack(alignment: .center) {
|
||||
TransportIcon(transportType: device.transportType)
|
||||
if device.isManualConnection && (device.longName != nil || device.shortName != nil) {
|
||||
VStack (alignment: .leading) {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Last seen device:")
|
||||
Text("\(String(describing: device))")
|
||||
}
|
||||
}
|
||||
}.padding(.top, 3.0)
|
||||
#else
|
||||
//Different alignment for Mac
|
||||
HStack(alignment: .firstTextBaseline){
|
||||
// Different alignment for Mac
|
||||
HStack(alignment: .firstTextBaseline) {
|
||||
TransportIcon(transportType: device.transportType)
|
||||
if device.isManualConnection && (device.longName != nil || device.shortName != nil) {
|
||||
Text("Last seen device: \(String(describing: device))")
|
||||
|
|
@ -625,4 +625,3 @@ struct DeviceConnectRow: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,25 +25,20 @@ struct DeviceOnboarding: View {
|
|||
/// The Title View
|
||||
var title: some View {
|
||||
VStack {
|
||||
Text("Welcome to")
|
||||
.font(.title2.bold())
|
||||
.multilineTextAlignment(.center)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Text("Meshtastic")
|
||||
.font(.largeTitle.bold())
|
||||
Text("Welcome to Meshtastic")
|
||||
.font(.title.bold())
|
||||
.multilineTextAlignment(.center)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
|
||||
var welcomeView: some View {
|
||||
VStack {
|
||||
VStack(spacing: 0) {
|
||||
ScrollView(.vertical) {
|
||||
VStack {
|
||||
// Title
|
||||
title
|
||||
.padding(.top)
|
||||
// Onboarding
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
makeRow(
|
||||
icon: "antenna.radiowaves.left.and.right",
|
||||
|
|
@ -63,14 +58,34 @@ struct DeviceOnboarding: View {
|
|||
makeRow(
|
||||
icon: "person.2.shield",
|
||||
title: String(localized: "User Privacy"),
|
||||
subtitle: String(localized: "Meshtastic does not collect any personal information. We do anonymously collect usage and crash data to improve the app. You can opt out under app settings.")
|
||||
subtitle: String(localized: "Meshtastic does not collect any personal information. We do anonymously collect usage and crash data to improve the app.")
|
||||
)
|
||||
makeRow(
|
||||
icon: "bell.badge",
|
||||
title: String(localized: "Message Notifications"),
|
||||
subtitle: String(localized: "Receive notifications for incoming messages and critical alerts even when the app is in the background.")
|
||||
)
|
||||
makeRow(
|
||||
icon: "custom.bluetooth",
|
||||
title: String(localized: "Bluetooth Connectivity"),
|
||||
subtitle: String(localized: "Connect to your Meshtastic node via Bluetooth Low Energy for the best messaging experience.")
|
||||
)
|
||||
makeRow(
|
||||
icon: "network",
|
||||
title: String(localized: "Local Network Access"),
|
||||
subtitle: String(localized: "Connect to nodes on your local Wi-Fi network.")
|
||||
)
|
||||
makeRow(
|
||||
icon: "car.fill",
|
||||
title: String(localized: "Siri & CarPlay"),
|
||||
subtitle: String(localized: "Send and receive Meshtastic messages hands-free using Siri and CarPlay.")
|
||||
)
|
||||
}
|
||||
.padding()
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom)
|
||||
}
|
||||
.interactiveDismissDisabled()
|
||||
}
|
||||
Spacer()
|
||||
.interactiveDismissDisabled()
|
||||
Button {
|
||||
Task {
|
||||
await goToNextStep(after: nil)
|
||||
|
|
@ -79,10 +94,7 @@ struct DeviceOnboarding: View {
|
|||
Text("Get started")
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.buttonStyle(.borderedProminent)
|
||||
.capsuleButtonStyle()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,10 +149,7 @@ struct DeviceOnboarding: View {
|
|||
Text("Configure notification permissions")
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.buttonStyle(.borderedProminent)
|
||||
.capsuleButtonStyle()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -206,10 +215,7 @@ struct DeviceOnboarding: View {
|
|||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.padding()
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.buttonStyle(.borderedProminent)
|
||||
.capsuleButtonStyle()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -266,10 +272,7 @@ struct DeviceOnboarding: View {
|
|||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.padding()
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.buttonStyle(.borderedProminent)
|
||||
.capsuleButtonStyle()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -316,10 +319,7 @@ struct DeviceOnboarding: View {
|
|||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.padding()
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.buttonStyle(.borderedProminent)
|
||||
.capsuleButtonStyle()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -361,10 +361,7 @@ struct DeviceOnboarding: View {
|
|||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.padding()
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.buttonStyle(.borderedProminent)
|
||||
.capsuleButtonStyle()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -372,7 +369,7 @@ struct DeviceOnboarding: View {
|
|||
VStack {
|
||||
ScrollView(.vertical) {
|
||||
VStack {
|
||||
Text("Siri & Shortcuts")
|
||||
Text("Siri, Shortcuts & CarPlay")
|
||||
.font(.largeTitle.bold())
|
||||
.multilineTextAlignment(.center)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
|
@ -382,6 +379,11 @@ struct DeviceOnboarding: View {
|
|||
.font(.body.bold())
|
||||
.multilineTextAlignment(.center)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
makeRow(
|
||||
icon: "car.fill",
|
||||
title: String(localized: "CarPlay Messaging"),
|
||||
subtitle: String(localized: "Read and reply to Meshtastic channel and direct messages directly from your car's display using CarPlay.")
|
||||
)
|
||||
makeRow(
|
||||
icon: "message",
|
||||
title: String(localized: "Send a Group Message"),
|
||||
|
|
@ -416,10 +418,7 @@ struct DeviceOnboarding: View {
|
|||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.padding()
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.buttonStyle(.borderedProminent)
|
||||
.capsuleButtonStyle()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -445,7 +444,37 @@ struct DeviceOnboarding: View {
|
|||
}
|
||||
.toolbar(.hidden)
|
||||
}
|
||||
|
||||
|
||||
@ViewBuilder
|
||||
func makeCompactRow(icon: String, title: String, subtitle: String) -> some View {
|
||||
HStack(alignment: .center, spacing: 12) {
|
||||
Group {
|
||||
if icon.starts(with: "custom.") {
|
||||
Image(icon)
|
||||
.resizable()
|
||||
.symbolRenderingMode(.multicolor)
|
||||
} else {
|
||||
Image(systemName: icon)
|
||||
.resizable()
|
||||
.symbolRenderingMode(.multicolor)
|
||||
}
|
||||
}
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 28, height: 28)
|
||||
.padding(.leading, 4)
|
||||
VStack(alignment: .leading, spacing: 1) {
|
||||
Text(title)
|
||||
.font(.footnote.weight(.semibold))
|
||||
.foregroundColor(.primary)
|
||||
Text(subtitle)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
.accessibilityElement(children: .combine)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func makeRow(
|
||||
icon: String,
|
||||
|
|
@ -474,11 +503,11 @@ struct DeviceOnboarding: View {
|
|||
}
|
||||
VStack(alignment: .leading) {
|
||||
Text(title)
|
||||
.font(.subheadline.weight(.semibold))
|
||||
.font(.footnote.weight(.semibold))
|
||||
.foregroundColor(.primary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Text(subtitle)
|
||||
.font(.subheadline)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}.multilineTextAlignment(.leading)
|
||||
|
|
@ -557,7 +586,7 @@ struct DeviceOnboarding: View {
|
|||
}
|
||||
|
||||
func createSiriString() -> AttributedString {
|
||||
var fullText = AttributedString("Meshtastic supports Siri and Shortcuts so you can control your mesh hands-free. You can update Siri permissions at any time from settings.")
|
||||
var fullText = AttributedString("Meshtastic supports Siri, Shortcuts, and CarPlay so you can send and receive messages hands-free. You can update Siri permissions at any time from settings.")
|
||||
if let range = fullText.range(of: "settings") {
|
||||
fullText[range].link = URL(string: UIApplication.openSettingsURLString)!
|
||||
fullText[range].foregroundColor = .blue
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ struct InvalidVersionTests {
|
|||
}
|
||||
|
||||
@Test func viewCreationWithEmptyVersions() {
|
||||
let view = InvalidVersion()
|
||||
let view = InvalidVersion(minimumVersion: "", version: "")
|
||||
#expect(view.minimumVersion == "")
|
||||
#expect(view.version == "")
|
||||
}
|
||||
|
|
|
|||
181
MeshtasticTests/DeviceOnboardingTests.swift
Normal file
181
MeshtasticTests/DeviceOnboardingTests.swift
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
//
|
||||
// DeviceOnboardingTests.swift
|
||||
// MeshtasticTests
|
||||
//
|
||||
// Copyright(c) Garth Vander Houwen 2026.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import Meshtastic
|
||||
|
||||
// MARK: - SetupGuide Enum
|
||||
|
||||
@Suite("DeviceOnboarding.SetupGuide")
|
||||
struct SetupGuideTests {
|
||||
|
||||
@Test func allCasesExist() {
|
||||
let cases: [DeviceOnboarding.SetupGuide] = [
|
||||
.notifications, .location, .backgroundActivity,
|
||||
.localNetwork, .bluetooth, .siri
|
||||
]
|
||||
#expect(cases.count == 6)
|
||||
}
|
||||
|
||||
@Test func isHashable() {
|
||||
var seen = Set<DeviceOnboarding.SetupGuide>()
|
||||
seen.insert(.notifications)
|
||||
seen.insert(.notifications) // duplicate should not grow set
|
||||
seen.insert(.siri)
|
||||
#expect(seen.count == 2)
|
||||
}
|
||||
|
||||
@Test func equality() {
|
||||
#expect(DeviceOnboarding.SetupGuide.bluetooth == .bluetooth)
|
||||
#expect(DeviceOnboarding.SetupGuide.notifications != .siri)
|
||||
#expect(DeviceOnboarding.SetupGuide.location != .backgroundActivity)
|
||||
}
|
||||
|
||||
@Test func allCasesAreUnique() {
|
||||
let cases: [DeviceOnboarding.SetupGuide] = [
|
||||
.notifications, .location, .backgroundActivity,
|
||||
.localNetwork, .bluetooth, .siri
|
||||
]
|
||||
let unique = Set(cases)
|
||||
#expect(unique.count == cases.count)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Attributed String Formatters
|
||||
|
||||
@Suite("DeviceOnboarding string formatters")
|
||||
struct OnboardingStringFormatterTests {
|
||||
|
||||
let view = DeviceOnboarding()
|
||||
|
||||
// Helpers
|
||||
private func hasSettingsLink(_ string: AttributedString) -> Bool {
|
||||
guard let range = string.range(of: "settings") else { return false }
|
||||
return string[range].link != nil
|
||||
}
|
||||
|
||||
private func settingsLinkURL(_ string: AttributedString) -> URL? {
|
||||
guard let range = string.range(of: "settings") else { return nil }
|
||||
return string[range].link
|
||||
}
|
||||
|
||||
@Test func backgroundActivityStringContainsText() {
|
||||
let string = view.createBackgroundActivityString()
|
||||
#expect(string.description.contains("background"))
|
||||
#expect(string.description.contains("settings"))
|
||||
}
|
||||
|
||||
@Test func backgroundActivityStringHasSettingsLink() {
|
||||
let string = view.createBackgroundActivityString()
|
||||
#expect(hasSettingsLink(string))
|
||||
}
|
||||
|
||||
@Test func backgroundActivitySettingsLinkIsAppSettings() {
|
||||
let string = view.createBackgroundActivityString()
|
||||
let url = settingsLinkURL(string)
|
||||
#expect(url?.scheme == "app-settings" || url?.absoluteString.contains("settings") == true)
|
||||
}
|
||||
|
||||
@Test func locationStringContainsText() {
|
||||
let string = view.createLocationString()
|
||||
#expect(string.description.contains("location"))
|
||||
#expect(string.description.contains("settings"))
|
||||
}
|
||||
|
||||
@Test func locationStringHasSettingsLink() {
|
||||
let string = view.createLocationString()
|
||||
#expect(hasSettingsLink(string))
|
||||
}
|
||||
|
||||
@Test func localNetworkStringContainsText() {
|
||||
let string = view.createLocalNetworkString()
|
||||
#expect(string.description.contains("local network") || string.description.contains("TCP"))
|
||||
#expect(string.description.contains("settings"))
|
||||
}
|
||||
|
||||
@Test func localNetworkStringHasSettingsLink() {
|
||||
let string = view.createLocalNetworkString()
|
||||
#expect(hasSettingsLink(string))
|
||||
}
|
||||
|
||||
@Test func bluetoothStringContainsText() {
|
||||
let string = view.createBluetoothString()
|
||||
#expect(string.description.contains("Bluetooth") || string.description.contains("BLE"))
|
||||
#expect(string.description.contains("settings"))
|
||||
}
|
||||
|
||||
@Test func bluetoothStringHasSettingsLink() {
|
||||
let string = view.createBluetoothString()
|
||||
#expect(hasSettingsLink(string))
|
||||
}
|
||||
|
||||
@Test func siriStringContainsCarPlay() {
|
||||
let string = view.createSiriString()
|
||||
#expect(string.description.contains("CarPlay"))
|
||||
}
|
||||
|
||||
@Test func siriStringContainsSiri() {
|
||||
let string = view.createSiriString()
|
||||
#expect(string.description.contains("Siri"))
|
||||
}
|
||||
|
||||
@Test func siriStringHasSettingsLink() {
|
||||
let string = view.createSiriString()
|
||||
#expect(hasSettingsLink(string))
|
||||
}
|
||||
|
||||
@Test func allStringsHaveSettingsLinks() {
|
||||
let strings = [
|
||||
view.createBackgroundActivityString(),
|
||||
view.createLocationString(),
|
||||
view.createLocalNetworkString(),
|
||||
view.createBluetoothString(),
|
||||
view.createSiriString()
|
||||
]
|
||||
for string in strings {
|
||||
#expect(hasSettingsLink(string), "Expected 'settings' link in: \(string)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Navigation Flow
|
||||
|
||||
@Suite("DeviceOnboarding navigation")
|
||||
struct OnboardingNavigationTests {
|
||||
|
||||
@Test func backgroundActivityAlwaysGoesToLocalNetwork() async {
|
||||
let view = DeviceOnboarding()
|
||||
await view.goToNextStep(after: .backgroundActivity)
|
||||
#expect(view.navigationPath == [.localNetwork])
|
||||
}
|
||||
|
||||
@Test func localNetworkAlwaysGoesToBluetooth() async {
|
||||
let view = DeviceOnboarding()
|
||||
await view.goToNextStep(after: .localNetwork)
|
||||
#expect(view.navigationPath == [.bluetooth])
|
||||
}
|
||||
|
||||
@Test func bluetoothAlwaysGoesToSiri() async {
|
||||
let view = DeviceOnboarding()
|
||||
await view.goToNextStep(after: .bluetooth)
|
||||
#expect(view.navigationPath == [.siri])
|
||||
}
|
||||
|
||||
@Test func navigationPathStartsEmpty() {
|
||||
let view = DeviceOnboarding()
|
||||
#expect(view.navigationPath.isEmpty)
|
||||
}
|
||||
|
||||
@Test func deterministicStepsAppendInOrder() async {
|
||||
let view = DeviceOnboarding()
|
||||
await view.goToNextStep(after: .backgroundActivity)
|
||||
await view.goToNextStep(after: .localNetwork)
|
||||
await view.goToNextStep(after: .bluetooth)
|
||||
#expect(view.navigationPath == [.localNetwork, .bluetooth, .siri])
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue