diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 8bef46b3..49adb40d 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -64,6 +64,8 @@ DD8ED9C8289CE4B900B3B0AB /* RoutingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8ED9C7289CE4B900B3B0AB /* RoutingError.swift */; }; DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860D26F69BAE00DC5189 /* NodeMap.swift */; }; DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD913638270DFF4C00D7ACF3 /* LocalNotificationManager.swift */; }; + DD97E96628EFD9820056DDA4 /* MeshtasticLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */; }; + DD97E96828EFE9A00056DDA4 /* About.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD97E96728EFE9A00056DDA4 /* About.swift */; }; DDA1C48E28DB49D3009933EC /* ChannelRoles.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA1C48D28DB49D3009933EC /* ChannelRoles.swift */; }; DDA6B2E928419CF2003E8C16 /* MeshPackets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6B2E828419CF2003E8C16 /* MeshPackets.swift */; }; DDA6B2EB28420A7B003E8C16 /* NodeAnnotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6B2EA28420A7B003E8C16 /* NodeAnnotation.swift */; }; @@ -176,6 +178,8 @@ DD90860A26F645B700DC5189 /* Meshtastic.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Meshtastic.entitlements; sourceTree = ""; }; DD90860D26F69BAE00DC5189 /* NodeMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMap.swift; sourceTree = ""; }; DD913638270DFF4C00D7ACF3 /* LocalNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNotificationManager.swift; sourceTree = ""; }; + DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticLogo.swift; sourceTree = ""; }; + DD97E96728EFE9A00056DDA4 /* About.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = About.swift; sourceTree = ""; }; DDA1C48D28DB49D3009933EC /* ChannelRoles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelRoles.swift; sourceTree = ""; }; DDA6B2E828419CF2003E8C16 /* MeshPackets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshPackets.swift; sourceTree = ""; }; DDA6B2EA28420A7B003E8C16 /* NodeAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeAnnotation.swift; sourceTree = ""; }; @@ -291,6 +295,7 @@ DD4A911C2708C57100501B7E /* Settings */ = { isa = PBXGroup; children = ( + DD97E96728EFE9A00056DDA4 /* About.swift */, DD3501882852FC3B000FC853 /* Settings.swift */, DD4A911D2708C65400501B7E /* AppSettings.swift */, DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */, @@ -508,6 +513,7 @@ DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */, DDB6ABDA28B0AC6000384BA1 /* DistanceText.swift */, DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */, + DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */, ); path = Helpers; sourceTree = ""; @@ -745,6 +751,7 @@ DD2553592855B52700E55709 /* PositionConfig.swift in Sources */, DDB3107228A6224100F1DE3D /* device_metadata.pb.swift in Sources */, DDAF8C6326ED0A230058C060 /* admin.pb.swift in Sources */, + DD97E96828EFE9A00056DDA4 /* About.swift in Sources */, DDB6ABE028B13AC700384BA1 /* DeviceRoles.swift in Sources */, DD86D40C287F401000BAEB7A /* SaveChannelQRCode.swift in Sources */, DDA1C48E28DB49D3009933EC /* ChannelRoles.swift in Sources */, @@ -772,6 +779,7 @@ DD415828285859C4009B0E59 /* TelemetryConfig.swift in Sources */, DD73FD1128750779000852D6 /* PositionLog.swift in Sources */, DD3CC6C028E7A60700FA9159 /* MessagingEnums.swift in Sources */, + DD97E96628EFD9820056DDA4 /* MeshtasticLogo.swift in Sources */, C9697F9D279336B700250207 /* LocalMBTileOverlay.swift in Sources */, DD0F791B28713C8A00A6FDAD /* AdminMessageList.swift in Sources */, DD3CC6BC28E366DF00FA9159 /* Meshtastic.xcdatamodeld in Sources */, diff --git a/Meshtastic/Assets.xcassets/logo-black.imageset/Contents.json b/Meshtastic/Assets.xcassets/logo-black.imageset/Contents.json new file mode 100644 index 00000000..5ef35f53 --- /dev/null +++ b/Meshtastic/Assets.xcassets/logo-black.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Mesh_Logo_Black_Small.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Mesh_Logo_Black.svg", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Mesh_Logo_Black_Large.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black.svg b/Meshtastic/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black.svg new file mode 100644 index 00000000..e0f9bb19 --- /dev/null +++ b/Meshtastic/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Meshtastic/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black_Large.svg b/Meshtastic/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black_Large.svg new file mode 100644 index 00000000..a3eec0a0 --- /dev/null +++ b/Meshtastic/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black_Large.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Meshtastic/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black_Small.svg b/Meshtastic/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black_Small.svg new file mode 100644 index 00000000..b13ff954 --- /dev/null +++ b/Meshtastic/Assets.xcassets/logo-black.imageset/Mesh_Logo_Black_Small.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Meshtastic/Assets.xcassets/logo-white.imageset/Contents.json b/Meshtastic/Assets.xcassets/logo-white.imageset/Contents.json new file mode 100644 index 00000000..c2d1f573 --- /dev/null +++ b/Meshtastic/Assets.xcassets/logo-white.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Mesh_Logo_White_Small.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Mesh_Logo_White.svg", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Mesh_Logo_White_Large.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/logo-white.imageset/Mesh_Logo_White.svg b/Meshtastic/Assets.xcassets/logo-white.imageset/Mesh_Logo_White.svg new file mode 100644 index 00000000..b1bcd575 --- /dev/null +++ b/Meshtastic/Assets.xcassets/logo-white.imageset/Mesh_Logo_White.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Meshtastic/Assets.xcassets/logo-white.imageset/Mesh_Logo_White_Large.svg b/Meshtastic/Assets.xcassets/logo-white.imageset/Mesh_Logo_White_Large.svg new file mode 100644 index 00000000..517dd23d --- /dev/null +++ b/Meshtastic/Assets.xcassets/logo-white.imageset/Mesh_Logo_White_Large.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Meshtastic/Assets.xcassets/logo-white.imageset/Mesh_Logo_White_Small.svg b/Meshtastic/Assets.xcassets/logo-white.imageset/Mesh_Logo_White_Small.svg new file mode 100644 index 00000000..fab02c18 --- /dev/null +++ b/Meshtastic/Assets.xcassets/logo-white.imageset/Mesh_Logo_White_Small.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/Meshtastic/MeshtasticApp.swift b/Meshtastic/MeshtasticApp.swift index 227f70c4..6dce5257 100644 --- a/Meshtastic/MeshtasticApp.swift +++ b/Meshtastic/MeshtasticApp.swift @@ -37,15 +37,20 @@ struct MeshtasticAppleApp: App { .sheet(isPresented: $saveQR) { SaveChannelQRCode(channelHash: channelUrl?.absoluteString ?? "Empty Channel URL") + .presentationDetents([.medium, .large]) + .presentationDragIndicator(.visible) } .onOpenURL(perform: { (url) in - print("QR Code URL received from the Camera \(url)") + print("Some sort of URL was received \(url)") channelUrl = url - print("User wants to open URL: \(channelUrl?.absoluteString ?? "No QR Code Link")") + if url.absoluteString.lowercased().contains("https://meshtastic.org/e/#") { saveQR = true + print("User wants to open a Channel Settings URL: \(channelUrl?.absoluteString ?? "No QR Code Link")") + } else { + print("User wants to import a MBTILES offline map file: \(channelUrl?.absoluteString ?? "No Tiles link")") } //we are expecting a .mbtiles map file that contains raster data @@ -60,7 +65,11 @@ struct MeshtasticAppleApp: App { try? fileManager.removeItem(atPath: destination.path) } - try? fileManager.copyItem(at: url, to: destination) + do { + try fileManager.copyItem(at: url, to: destination) + } catch { + print("Copy MB Tile file failed. Error: \(error)") + } if (fileManager.fileExists(atPath: destination.path)) { print("ℹ️ Saved the map file") diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index b10711d0..673415e0 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -253,24 +253,25 @@ struct Connect: View { } - .navigationTitle("Bluetooth Radios") - .navigationBarItems(trailing: + .navigationTitle("Bluetooth") + + .navigationBarItems(leading: + MeshtasticLogo(), + trailing: - ZStack { - - ConnectedDevice( - bluetoothOn: self.bleManager.isSwitchedOn, - deviceConnected: self.bleManager.connectedPeripheral != nil, - name: (bleManager.connectedPeripheral != nil) ? self.bleManager.connectedPeripheral.shortName : - "????") - } - ) + ZStack { + + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????") + }) } .navigationViewStyle(StackNavigationViewStyle()) .sheet(isPresented: $invalidFirmwareVersion, onDismiss: didDismissSheet) { InvalidVersion(minimumVersion: self.bleManager.minimumVersion, version: self.bleManager.connectedVersion) + .presentationDetents([.large]) + .presentationDragIndicator(.automatic) } + .onChange(of: (self.bleManager.invalidVersion)) { cv in diff --git a/Meshtastic/Views/Helpers/MeshtasticLogo.swift b/Meshtastic/Views/Helpers/MeshtasticLogo.swift new file mode 100644 index 00000000..52713591 --- /dev/null +++ b/Meshtastic/Views/Helpers/MeshtasticLogo.swift @@ -0,0 +1,22 @@ +// +// MeshtasticLogo.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 10/6/22. +// +import SwiftUI + +struct MeshtasticLogo: View { + + @Environment(\.colorScheme) var colorScheme + + var body: some View { + VStack { + Image(colorScheme == .dark ? "logo-white" : "logo-black") + .resizable() + .scaledToFit() + } + .padding(.bottom, 5) + .offset(x: -15) + } +} diff --git a/Meshtastic/Views/Messages/Contacts.swift b/Meshtastic/Views/Messages/Contacts.swift index 76160113..325ec948 100644 --- a/Meshtastic/Views/Messages/Contacts.swift +++ b/Meshtastic/Views/Messages/Contacts.swift @@ -133,6 +133,9 @@ struct Contacts: View { } .navigationTitle("Contacts") .navigationBarTitleDisplayMode(.inline) + .navigationBarItems(leading: + MeshtasticLogo() + ) } .listStyle(PlainListStyle()) } diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 2ab5327a..dc74e3cd 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -127,6 +127,9 @@ struct NodeList: View { } } .navigationTitle("All Nodes") + .navigationBarItems(leading: + MeshtasticLogo() + ) .onAppear { if initialLoad { diff --git a/Meshtastic/Views/Nodes/NodeMap.swift b/Meshtastic/Views/Nodes/NodeMap.swift index b8d715e4..22f174cf 100644 --- a/Meshtastic/Views/Nodes/NodeMap.swift +++ b/Meshtastic/Views/Nodes/NodeMap.swift @@ -118,7 +118,8 @@ struct NodeMap: View { .navigationTitle("Mesh Map") .navigationBarTitleDisplayMode(.inline) - .navigationBarItems(trailing: + .navigationBarItems(leading: + MeshtasticLogo(), trailing: ZStack { diff --git a/Meshtastic/Views/Settings/About.swift b/Meshtastic/Views/Settings/About.swift new file mode 100644 index 00000000..d880b3fe --- /dev/null +++ b/Meshtastic/Views/Settings/About.swift @@ -0,0 +1,56 @@ +// +// About.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 10/6/22. +// +import SwiftUI +import StoreKit + +struct AboutMeshtastic: View { + + let locale = Locale.current + + var body: some View { + + VStack{ + + List { + Section(header: Text("What is Meshtastic?")) { + Text("An open source, off-grid, decentralized, mesh network built to run on affordable, low-power devices.") + .font(.title3) + + } + Section(header: Text("Apple Apps")) { + Button("Review the app") { + if let scene = UIApplication.shared.connectedScenes + .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene { + SKStoreReviewController.requestReview(in: scene) + } + } + .font(.title2) + Link("Sponsor App Development", destination: URL(string: "https://github.com/sponsors/garthvh")!) + .font(.title2) + Link("GitHub Repository", destination: URL(string: "https://github.com/meshtastic/Meshtastic-Apple")!) + .font(.title2) + } + if locale.region?.identifier == "US" { + Section(header: Text("Get Devices")) { + Link("Buy Complete Radios", destination: URL(string: "https://www.etsy.com/shop/GarthVH")!) + .font(.title2) + } + } + Section(header: Text("Project information")) { + Link("Website", destination: URL(string: "https://meshtastic.org")!) + .font(.title2) + Link("Documentation", destination: URL(string: "https://meshtastic.org/docs/getting-started")!) + .font(.title2) + } + Text("Meshtastic Copyright(c) Meshtastic LLC") + .font(.caption) + } + } + .navigationTitle("About") + .navigationBarTitleDisplayMode(.inline) + } +} diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index 2c39d4d9..241f828c 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -75,12 +75,11 @@ struct DeviceConfig: View { titleVisibility: .visible ) { Button("Erase all device and app data?", role: .destructive) { - if !bleManager.sendNodeDBReset(destNum: bleManager.connectedPeripheral.num) { - print("NodeDB Reset Failed") - } else { - // Disconnect from device as we are going to wipe the app database now - bleManager.disconnectPeripheral() + if bleManager.sendNodeDBReset(destNum: bleManager.connectedPeripheral.num) { + bleManager.disconnectPeripheral() clearCoreDataDatabase(context: context) + } else { + print("NodeDB Reset Failed") } } } @@ -99,13 +98,11 @@ struct DeviceConfig: View { ) { Button("Factory reset your device and app? ", role: .destructive) { - if !bleManager.sendFactoryReset(destNum: bleManager.connectedPeripheral.num) { - - print("Factory Reset Failed") - } else { - clearCoreDataDatabase(context: context) - // Disconnect from device + if bleManager.sendFactoryReset(destNum: bleManager.connectedPeripheral.num) { bleManager.disconnectPeripheral() + clearCoreDataDatabase(context: context) + } else { + print("Factory Reset Failed") } } diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index ad33e119..8a82e2c7 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -206,8 +206,20 @@ struct Settings: View { } } - // Not Implemented: - // Store Forward Config - Not Working, TBEAM Only + Section(header: Text("About")) { + + NavigationLink { + + AboutMeshtastic() + + } label: { + + Image(systemName: "questionmark.app") + .symbolRenderingMode(.hierarchical) + + Text("About Meshtastic") + } + } } .onAppear { @@ -218,6 +230,9 @@ struct Settings: View { } .listStyle(GroupedListStyle()) .navigationTitle("Settings") + .navigationBarItems(leading: + MeshtasticLogo() + ) } } } diff --git a/Meshtastic/Views/Settings/ShareChannels.swift b/Meshtastic/Views/Settings/ShareChannels.swift index ea89cb6d..445903e0 100644 --- a/Meshtastic/Views/Settings/ShareChannels.swift +++ b/Meshtastic/Views/Settings/ShareChannels.swift @@ -136,8 +136,6 @@ struct ShareChannels: View { let qrImage = qrCodeImage.generateQRCode(from: channelsUrl) VStack { - - Divider() ShareLink("Share QR Code & Link", item: Image(uiImage: qrImage), @@ -146,7 +144,7 @@ struct ShareChannels: View { preview: SharePreview("Meshtastic Node \(node?.user?.shortName ?? "????") has shared channels with you", image: Image(uiImage: qrImage)) ) - .presentationDetents([.large, .large]) + Divider()