Add missing SwiftUI #Preview blocks across 65 views (#1649)

* Add SwiftUI previews for simple helper views

Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/a2a43e8c-24fd-443a-8a98-13b678770edd

Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>

* Add previews for action buttons, ChannelForm, MetricsColumnDetail, and DeviceOnboarding

Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/a2a43e8c-24fd-443a-8a98-13b678770edd

Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>

* Add previews for config views, log views, AppLog, Firmware, AppData, and UserConfig

Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/a2a43e8c-24fd-443a-8a98-13b678770edd

Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>

* Add preview for PositionConfig

Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/a2a43e8c-24fd-443a-8a98-13b678770edd

Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>

* Fix formatting bugs in #Preview blocks: restore missing .environmentObject/.environment modifiers and add proper tab indentation

Agent-Logs-Url: https://github.com/meshtastic/Meshtastic-Apple/sessions/7eeb7a54-7928-466f-8e39-b00d0012a09d

Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>

* Linting fixes

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: garthvh <1795163+garthvh@users.noreply.github.com>
Co-authored-by: Garth Vander Houwen <garthvh@yahoo.com>
This commit is contained in:
Copilot 2026-04-04 18:02:32 -07:00 committed by GitHub
parent f5afce2d0f
commit 894e9382d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
76 changed files with 567 additions and 41 deletions

View file

@ -59,8 +59,7 @@ extension MessageEntity {
let users = try context.fetch(request)
// If exactly one match is found, return its name
if users.count == 1, let name = users.first?.longName, !name.isEmpty
{
if users.count == 1, let name = users.first?.longName, !name.isEmpty {
return "\(name)"
}

View file

@ -1278,4 +1278,3 @@ actor MeshPackets {
}
}
}

View file

@ -184,4 +184,3 @@ extension MqttClientProxyManager: CocoaMQTTDelegate {
Logger.mqtt.debug("📲 [MQTT Client Proxy] pong")
}
}

View file

@ -71,10 +71,7 @@ final class CoTXMLParser: NSObject, XMLParserDelegate {
}
// MARK: - XMLParserDelegate
func parser(_ parser: XMLParser, didStartElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?,
attributes attributeDict: [String: String] = [:]) {
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String] = [:]) {
elementStack.append(elementName)
currentElement = elementName
currentText = ""
@ -138,8 +135,7 @@ final class CoTXMLParser: NSObject, XMLParserDelegate {
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?) {
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "remarks" {
remarksText = currentText.trimmingCharacters(in: .whitespacesAndNewlines)
}

View file

@ -494,4 +494,3 @@ enum TAKConnectionError: LocalizedError {
}
}
}

View file

@ -565,18 +565,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))")
@ -609,4 +609,3 @@ struct DeviceConnectRow: View {
}
}
}

View file

@ -62,3 +62,7 @@ struct InvalidVersion: View {
}
}
}
#Preview {
InvalidVersion(minimumVersion: "2.5.4", version: "2.3.0")
}

View file

@ -94,3 +94,11 @@ enum BLESignalStrength: Int {
case normal = 1
case strong = 2
}
#Preview {
HStack(spacing: 16) {
SignalStrengthIndicator(signalStrength: .weak)
SignalStrengthIndicator(signalStrength: .normal)
SignalStrengthIndicator(signalStrength: .strong)
}
}

View file

@ -111,3 +111,15 @@ struct BatteryCompact: View {
} ?? "Unknown")
}
}
#Preview {
VStack(spacing: 12) {
BatteryCompact(batteryLevel: 75, font: .caption, iconFont: .caption, color: .gray)
BatteryCompact(batteryLevel: 50, font: .caption, iconFont: .caption, color: .gray)
BatteryCompact(batteryLevel: 25, font: .caption, iconFont: .caption, color: .gray)
BatteryCompact(batteryLevel: 10, font: .caption, iconFont: .caption, color: .gray)
BatteryCompact(batteryLevel: 100, font: .caption, iconFont: .caption, color: .gray)
BatteryCompact(batteryLevel: 101, font: .caption, iconFont: .caption, color: .gray)
BatteryCompact(batteryLevel: nil, font: .caption, iconFont: .caption, color: .gray)
}
}

View file

@ -32,3 +32,15 @@ struct ChannelLock: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let encryptedChannel = ChannelEntity(context: context)
encryptedChannel.psk = Data([0x01, 0x02, 0x03, 0x04])
let unencryptedChannel = ChannelEntity(context: context)
unencryptedChannel.psk = Data()
return HStack(spacing: 16) {
ChannelLock(channel: encryptedChannel)
ChannelLock(channel: unencryptedChannel)
}
}

View file

@ -38,7 +38,7 @@ struct CompassView: View {
}
// Trigger a vibration if aligned with waypoint
private func checkAlignment(bearing: Double,heading: Double) {
private func checkAlignment(bearing: Double, heading: Double) {
// Compute minimal angular difference between heading and bearing in [0, 180]
let rawDiff = abs(heading - bearing).truncatingRemainder(dividingBy: 360)
let diff = min(rawDiff, 360 - rawDiff)
@ -53,7 +53,6 @@ struct CompassView: View {
inAlignment = false
}
}
private func distanceToWaypoint() -> CLLocationDistance? {
guard
@ -76,7 +75,6 @@ struct CompassView: View {
return formatter.string(from: measurement)
}
var body: some View {
NavigationStack {
VStack(spacing: 15) {
@ -88,14 +86,14 @@ struct CompassView: View {
.foregroundColor(color)
if let wp = waypointLocation {
HStack{
HStack {
Image(systemName: "mappin.and.ellipse")
Text("\(String(format: "%.4f", wp.latitude)), \(String(format: "%.4f", wp.longitude))")
.font(.subheadline)
}
if let distance = distanceToWaypoint() {
HStack{
HStack {
Image(systemName: "lines.measurement.horizontal")
Text("Distance: \(formatDistance(distance))")
.font(.subheadline)
@ -137,7 +135,7 @@ struct CompassView: View {
)
// Move waypoint marker outside compass
.onChange(of: locationsHandler.heading) { _, _ in
checkAlignment(bearing: bearing,heading:locationsHandler.heading)
checkAlignment(bearing: bearing, heading:locationsHandler.heading)
}
}
@ -159,9 +157,7 @@ struct CompassView: View {
}
}
// MARK: - Waypoint Marker View
struct WaypointMarkerView: View {
let bearing: Double
let compassDegrees: Double
@ -177,9 +173,7 @@ struct WaypointMarkerView: View {
}
// MARK: - Bearing Calculator
struct BearingCalculator {
static func bearingBetween(
@ -205,9 +199,7 @@ struct BearingCalculator {
}
}
// MARK: - Marker Model
struct Marker: Hashable {
let degrees: Double
let label: String
@ -239,9 +231,7 @@ struct Marker: Hashable {
}
}
// MARK: - Compass Marker View
struct CompassMarkerView: View {
let marker: Marker
let compassDegrees: Double
@ -281,9 +271,7 @@ struct CompassMarkerView: View {
}
}
// MARK: - Preview
struct CompassView_Previews: PreviewProvider {
static var previews: some View {
CompassView(

View file

@ -28,3 +28,11 @@ struct DateTimeText: View {
}
}
}
#Preview {
VStack {
DateTimeText(dateTime: Date())
DateTimeText(dateTime: Calendar.current.date(byAdding: .day, value: -1, to: Date()))
DateTimeText(dateTime: nil)
}
}

View file

@ -51,3 +51,8 @@ struct MeshtasticLogo: View {
#endif
}
}
#Preview {
MeshtasticLogo()
.frame(width: 200, height: 44)
}

View file

@ -36,3 +36,15 @@ struct MessageTemplate: View {
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let user = UserEntity(context: context)
user.longName = "Test User"
user.shortName = "TU"
let message = MessageEntity(context: context)
message.messagePayload = "Hello, World!"
message.messageTimestamp = Int32(Date().timeIntervalSince1970)
message.replyID = 0
return MessageTemplate(user: user, message: message)
}

View file

@ -94,3 +94,15 @@ struct PowerMetricCompactWidget: View {
.background(.tertiary, in: RoundedRectangle(cornerRadius: 20, style: .continuous))
}
}
#Preview {
let gridItemLayout = Array(repeating: GridItem(.flexible(), spacing: 10), count: 2)
Form {
LazyVGrid(columns: gridItemLayout) {
PowerMetricCompactWidget(type: .voltage, value: 3.72, title: "Channel 1 Voltage")
PowerMetricCompactWidget(type: .current, value: 125.3, title: "Channel 1 Current")
PowerMetricCompactWidget(type: .voltage, value: 5.01, title: "Channel 2 Voltage")
PowerMetricCompactWidget(type: .current, value: 42.7, title: "Channel 2 Current")
}
}
}

View file

@ -119,3 +119,12 @@ struct LEDIndicator: View {
}
}
}
#Preview {
HStack(spacing: 12) {
LEDIndicator(flash: .constant(1), color: .green)
.frame(width: 10, height: 10)
LEDIndicator(flash: .constant(0), color: .red)
.frame(width: 10, height: 10)
}
}

View file

@ -45,6 +45,16 @@ public struct RateLimitedButton<Content: View>: View {
}
}
#Preview {
RateLimitedButton(key: "preview", rateLimit: 30, action: { }) { rateLimitInfo in
if let info = rateLimitInfo {
Label("\(Int(info.secondsRemaining))s", systemImage: "clock")
} else {
Label("Send", systemImage: "paperplane")
}
}
}
// To store the time an action occured (name by a key) and the time limit
// Does not persist across app launches
class RateLimitStorage: ObservableObject {

View file

@ -69,3 +69,11 @@ struct SecureInput: View {
}
}
}
#Preview {
List {
SecureInput("Password", text: .constant("s3cretP@ss"), isValid: .constant(true))
SecureInput("Invalid Key", text: .constant("short"), isValid: .constant(false))
SecureInput("Empty", text: .constant(""), isValid: .constant(true))
}
}

View file

@ -118,3 +118,7 @@ func calculateDewPoint(temp: Float, relativeHumidity: Float, convertToLocale: Bo
}
return dewPointUnit.converted(to: format).value
}
#Preview {
LocalWeatherConditions(location: CLLocation(latitude: 47.6062, longitude: -122.3321))
}

View file

@ -22,6 +22,13 @@ struct TraceRouteComponent<V: View>: View {
}
}
#Preview {
TraceRouteComponent {
Image(systemName: "antenna.radiowaves.left.and.right")
.font(.title)
}
}
struct TraceRoute: Layout {
var animatableData: AnimatablePair<CGFloat, CGFloat> {
get {

View file

@ -56,8 +56,6 @@ struct MessageContextMenuItems: View {
let sixMonthsAgo = Calendar.current.date(byAdding: .month, value: -6, to: Date())
// Compute a relay display string if relayNode is present
VStack {
Text("\(messageDate.formattedDate(format: MessageText.dateFormatString))")
.foregroundColor(.gray)

View file

@ -79,6 +79,12 @@ struct TapbackInputView: View {
}
}
#Preview {
TapbackInputView(text: .constant(""), isPresented: .constant(true)) { emoji in
print("Selected: \(emoji)")
}
}
extension UIView {
var firstResponder: UIView? {
guard !isFirstResponder else { return self }
@ -90,4 +96,3 @@ extension UIView {
return nil
}
}

View file

@ -141,3 +141,16 @@ struct DetectionSensorLog: View {
)
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
node.user = user
return DetectionSensorLog(node: node)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -254,3 +254,16 @@ struct DeviceMetricsLog: View {
)
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
node.user = user
return DeviceMetricsLog(node: node)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -186,3 +186,16 @@ struct EnvironmentMetricsLog: View {
return lower...upper
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
node.user = user
return EnvironmentMetricsLog(node: node)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -40,3 +40,13 @@ struct ClientHistoryButton: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let connectedNode = NodeInfoEntity(context: context)
connectedNode.num = 987654321
return ClientHistoryButton(connectedNode: connectedNode, node: node)
.environmentObject(AccessoryManager.shared)
}

View file

@ -64,3 +64,14 @@ struct DeleteNodeButton: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let connectedNode = NodeInfoEntity(context: context)
connectedNode.num = 987654321
let node = NodeInfoEntity(context: context)
node.num = 123456789
return DeleteNodeButton(connectedNode: connectedNode, node: node)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -61,3 +61,13 @@ struct ExchangePositionsButton: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let connectedNode = NodeInfoEntity(context: context)
connectedNode.num = 987654321
return ExchangePositionsButton(node: node, connectedNode: connectedNode)
.environmentObject(AccessoryManager.shared)
}

View file

@ -59,3 +59,13 @@ struct ExchangeUserInfoButton: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let connectedNode = NodeInfoEntity(context: context)
connectedNode.num = 987654321
return ExchangeUserInfoButton(node: node, connectedNode: connectedNode)
.environmentObject(AccessoryManager.shared)
}

View file

@ -79,3 +79,16 @@ struct FavoriteNodeButton: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
node.user = user
return FavoriteNodeButton(node: node)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -51,3 +51,12 @@ struct IgnoreNodeButton: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
return IgnoreNodeButton(node: node)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -54,3 +54,15 @@ struct NavigateToButton: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
user.num = 123456789
node.user = user
return NavigateToButton(node: node)
}

View file

@ -31,3 +31,14 @@ struct NodeAlertsButton: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
node.user = user
return NodeAlertsButton(context: context, node: node, user: user)
}

View file

@ -43,3 +43,15 @@ struct TraceRouteButton: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
node.user = user
return TraceRouteButton(node: node)
.environmentObject(AccessoryManager.shared)
}

View file

@ -51,6 +51,14 @@ struct AnimatedNodePin: View, Equatable {
}
}
#Preview {
VStack(spacing: 20) {
AnimatedNodePin(nodeColor: .systemBlue, shortName: "TN", hasDetectionSensorMetrics: false, isOnline: true, calculatedDelay: 0.0)
AnimatedNodePin(nodeColor: .systemGreen, shortName: "AB", hasDetectionSensorMetrics: true, isOnline: true, calculatedDelay: 0.2)
AnimatedNodePin(nodeColor: .systemRed, shortName: "XY", hasDetectionSensorMetrics: false, isOnline: false, calculatedDelay: 0.0)
}
}
struct PulsingCircle: View {
let nodeColor: UIColor
let calculatedDelay: Double

View file

@ -228,3 +228,13 @@ struct MapSettingsForm: View {
}
}
#Preview {
MapSettingsForm(
traffic: .constant(false),
pointsOfInterest: .constant(true),
mapLayer: .constant(.standard),
meshMap: .constant(true),
enabledOverlayConfigs: .constant(Set<UUID>())
)
}

View file

@ -99,3 +99,10 @@ struct MetricsColumnDetail: View {
.interactiveDismissDisabled(false)
}
}
#Preview {
MetricsColumnDetail(
columnList: MetricsColumnList(columns: []),
seriesList: MetricsSeriesList()
)
}

View file

@ -208,3 +208,7 @@ struct NodeListFilter: View {
.presentationBackgroundInteraction(.enabled(upThrough: .large))
}
}
#Preview {
NodeListFilter(filters: NodeFilterParameters())
}

View file

@ -224,3 +224,16 @@ struct PaxCounterLog: View {
)
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
node.user = user
return PaxCounterLog(node: node)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -181,3 +181,16 @@ struct PositionLog: View {
})
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
node.user = user
return PositionLog(node: node)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -297,3 +297,16 @@ struct PowerMetricsLog: View {
)
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
node.user = user
return PowerMetricsLog(node: node)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -287,3 +287,16 @@ func getTraceRouteHops(context: NSManagedObjectContext) -> [TraceRouteHopEntity]
array.append(trh8)
return array
}
#Preview {
let context = PersistenceController.preview.container.viewContext
let node = NodeInfoEntity(context: context)
node.num = 123456789
let user = UserEntity(context: context)
user.longName = "Test Node"
user.shortName = "TN"
node.user = user
return TraceRouteLog(node: node)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -454,3 +454,8 @@ struct DeviceOnboarding: View {
}
}
#Preview {
DeviceOnboarding()
.environmentObject(AccessoryManager.shared)
}

View file

@ -67,3 +67,9 @@ struct AboutMeshtastic: View {
.navigationBarTitleDisplayMode(.inline)
}
}
#Preview {
NavigationView {
AboutMeshtastic()
}
}

View file

@ -143,3 +143,10 @@ struct AppData: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return AppData()
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -271,3 +271,7 @@ extension AppLog {
}
extension OSLogEntry: @retroactive Identifiable { }
#Preview {
AppLog()
}

View file

@ -250,3 +250,21 @@ struct ChannelForm: View {
}
}
}
#Preview {
ChannelForm(
channelIndex: .constant(0),
channelName: .constant("LongFast"),
channelKeySize: .constant(32),
channelKey: .constant("AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE="),
channelRole: .constant(1),
uplink: .constant(false),
downlink: .constant(false),
positionPrecision: .constant(14),
preciseLocation: .constant(false),
positionsEnabled: .constant(true),
hasChanges: .constant(false),
hasValidKey: .constant(true),
supportedVersion: .constant(true)
)
}

View file

@ -147,3 +147,10 @@ struct BluetoothConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return BluetoothConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -37,3 +37,13 @@ struct ConfigHeader<T>: View {
}
}
}
#Preview {
ConfigHeader(
title: "Bluetooth Configuration",
config: \NodeInfoEntity.bluetoothConfig,
node: nil,
onAppear: { }
)
.environmentObject(AccessoryManager.shared)
}

View file

@ -345,3 +345,10 @@ struct DeviceConfig: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return DeviceConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -235,3 +235,10 @@ struct DisplayConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return DisplayConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -321,3 +321,10 @@ struct LoRaConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return LoRaConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -134,3 +134,10 @@ struct AmbientLightingConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return AmbientLightingConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -355,3 +355,10 @@ struct CannedMessagesConfig: View {
self.hasMessagesChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return CannedMessagesConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -261,3 +261,10 @@ struct DetectionSensorConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return DetectionSensorConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -283,3 +283,9 @@ struct ExternalNotificationConfig: View {
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return ExternalNotificationConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -464,3 +464,10 @@ struct MQTTConfig: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return MQTTConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -123,3 +123,10 @@ struct PaxCounterConfig: View {
paxcounterUpdateInterval = UpdateInterval(from: Int(node?.paxCounterConfig?.updateInterval ?? 1800))
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return PaxCounterConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -143,3 +143,10 @@ struct RangeTestConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return RangeTestConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -114,3 +114,10 @@ struct RtttlConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return RtttlConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -205,3 +205,10 @@ struct SerialConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return SerialConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -197,3 +197,10 @@ struct StoreForwardConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return StoreForwardConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -241,3 +241,10 @@ struct TelemetryConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return TelemetryConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -209,3 +209,10 @@ struct NetworkConfig: View {
self.hasChanges = false
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return NetworkConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -562,3 +562,10 @@ struct PositionConfig: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return PositionConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -226,3 +226,10 @@ private struct FloatField: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return PowerConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -58,3 +58,8 @@ struct SaveConfigButton: View {
}
}
}
#Preview {
SaveConfigButton(node: nil, hasChanges: .constant(true), onConfirmation: { })
.environmentObject(AccessoryManager.shared)
}

View file

@ -428,3 +428,10 @@ struct SecurityConfig: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return SecurityConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -206,3 +206,10 @@ struct Firmware: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return Firmware(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -65,3 +65,7 @@ struct GPSStatus: View {
}
}
}
#Preview {
GPSStatus()
}

View file

@ -169,3 +169,7 @@ struct AppLogFilter: View {
.presentationBackgroundInteraction(.enabled(upThrough: .medium))
}
}
#Preview {
AppLogFilter(categories: .constant(Set<Int>()), levels: .constant(Set<Int>()))
}

View file

@ -424,9 +424,7 @@ struct TAKServerConfig: View {
}
}
// MARK: - Channel Label
@ViewBuilder
private func channelLabel(_ channel: ChannelEntity) -> some View {
if channel.name?.isEmpty ?? false {

View file

@ -55,3 +55,11 @@ struct UpdateIntervalPicker: View {
}
}
}
#Preview {
UpdateIntervalPicker(
config: .broadcastShort,
pickerLabel: "Update Interval",
selectedInterval: .constant(UpdateInterval(from: 30))
)
}

View file

@ -253,3 +253,10 @@ struct UserConfig: View {
}
}
}
#Preview {
let context = PersistenceController.preview.container.viewContext
return UserConfig(node: nil)
.environmentObject(AccessoryManager.shared)
.environment(\.managedObjectContext, context)
}

View file

@ -55,7 +55,7 @@ struct DeviceTests {
(-80, BLESignalStrength.normal),
(-84, BLESignalStrength.normal),
(-85, BLESignalStrength.weak),
(-100, BLESignalStrength.weak),
(-100, BLESignalStrength.weak)
])
func signalStrength(rssi: Int, expected: BLESignalStrength) {
let device = Device(
@ -209,7 +209,7 @@ struct TransportTypeTests {
@Test(arguments: [
(TransportType.ble, "BLE"),
(TransportType.tcp, "TCP"),
(TransportType.serial, "Serial"),
(TransportType.serial, "Serial")
])
func rawValues(type: TransportType, expected: String) {
#expect(type.rawValue == expected)
@ -307,7 +307,7 @@ struct NavigationStateTests {
NavigationState.Tab.connect,
NavigationState.Tab.nodes,
NavigationState.Tab.map,
NavigationState.Tab.settings,
NavigationState.Tab.settings
])
func tabRawValues(tab: NavigationState.Tab) {
#expect(NavigationState.Tab(rawValue: tab.rawValue) == tab)

View file

@ -214,7 +214,7 @@ struct RouterTests {
("debugLogs", SettingsNavigationState.debugLogs),
("appFiles", SettingsNavigationState.appFiles),
("firmwareUpdates", SettingsNavigationState.firmwareUpdates),
("tak", SettingsNavigationState.tak),
("tak", SettingsNavigationState.tak)
])
func routeSettingsPage(path: String, expected: SettingsNavigationState) async throws {
try await assertRoute(