Merge pull request #240 from meshtastic/2.0.3_Working_Changes

Add images for new heltec hardware, update protobufs
This commit is contained in:
Garth Vander Houwen 2022-11-17 23:06:00 -08:00 committed by GitHub
commit 55ecc35a30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 225 additions and 144 deletions

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "Heltec_turq 1.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Heltec_turq 2.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Heltec_turq.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "Heltec_turq 1.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Heltec_turq 2.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Heltec_turq.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "play_store_icon_114px-2.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "play_store_icon_114px-3.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "play_store_icon_114px-4.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -29,35 +29,34 @@ struct MeshtasticAppleApp: App {
.onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { userActivity in
print("URL received \(userActivity)")
incomingUrl = userActivity.webpageURL
self.incomingUrl = userActivity.webpageURL
if incomingUrl!.absoluteString.lowercased().contains("meshtastic.org/e/#") {
if self.incomingUrl!.absoluteString.lowercased().contains("meshtastic.org/e/#") {
if let components = incomingUrl?.absoluteString.components(separatedBy: "#") {
channelSettings = components.last!
if let components = self.incomingUrl?.absoluteString.components(separatedBy: "#") {
self.channelSettings = components.last!
}
saveChannels = true
print("User wants to open a Channel Settings URL: \(incomingUrl?.absoluteString ?? "No QR Code Link")")
self.saveChannels = true
print("User wants to open a Channel Settings URL: \(self.incomingUrl?.absoluteString ?? "No QR Code Link")")
}
if saveChannels {
print("User wants to open Channel Settings URL: \(String(describing: incomingUrl!.relativeString))")
if self.saveChannels {
print("User wants to open Channel Settings URL: \(String(describing: self.incomingUrl!.relativeString))")
}
}
.onOpenURL(perform: { (url) in
print("Some sort of URL was received \(url)")
incomingUrl = url
self.incomingUrl = url
if url.absoluteString.lowercased().contains("meshtastic.org/e/#") {
if let components = incomingUrl?.absoluteString.components(separatedBy: "#") {
channelSettings = components.last!
if let components = self.incomingUrl?.absoluteString.components(separatedBy: "#") {
self.channelSettings = components.last!
}
saveChannels = true
print("User wants to open a Channel Settings URL: \(incomingUrl?.absoluteString ?? "No QR Code Link")")
self.saveChannels = true
print("User wants to open a Channel Settings URL: \(self.incomingUrl?.absoluteString ?? "No QR Code Link")")
} else {
saveChannels = false
print("User wants to import a MBTILES offline map file: \(incomingUrl?.absoluteString ?? "No Tiles link")")
print("User wants to import a MBTILES offline map file: \(self.incomingUrl?.absoluteString ?? "No Tiles link")")
}
//we are expecting a .mbtiles map file that contains raster data
@ -66,7 +65,7 @@ struct MeshtasticAppleApp: App {
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let destination = documentsDirectory.appendingPathComponent("offline_map.mbtiles", isDirectory: false)
if !saveChannels {
if !self.saveChannels {
//do we need to delete an old one?
if (fileManager.fileExists(atPath: destination.path)) {
print(" Found an old map file. Deleting it")
@ -91,7 +90,6 @@ struct MeshtasticAppleApp: App {
}
})
}
.onChange(of: scenePhase) { (newScenePhase) in
switch newScenePhase {
case .background:

View file

@ -142,6 +142,14 @@ enum HardwareModel: SwiftProtobuf.Enum {
/// M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, Paper) https://m5stack.com/
case m5Stack // = 42
///
/// New Heltec LoRA32 with ESP32-S3 CPU
case heltecV3 // = 43
///
/// New Heltec Wireless Stick Lite with ESP32-S3 CPU
case heltecWslV3 // = 44
///
/// Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
case privateHw // = 255
@ -181,6 +189,8 @@ enum HardwareModel: SwiftProtobuf.Enum {
case 40: self = .nrf52840Pca10059
case 41: self = .drDev
case 42: self = .m5Stack
case 43: self = .heltecV3
case 44: self = .heltecWslV3
case 255: self = .privateHw
default: self = .UNRECOGNIZED(rawValue)
}
@ -216,6 +226,8 @@ enum HardwareModel: SwiftProtobuf.Enum {
case .nrf52840Pca10059: return 40
case .drDev: return 41
case .m5Stack: return 42
case .heltecV3: return 43
case .heltecWslV3: return 44
case .privateHw: return 255
case .UNRECOGNIZED(let i): return i
}
@ -256,6 +268,8 @@ extension HardwareModel: CaseIterable {
.nrf52840Pca10059,
.drDev,
.m5Stack,
.heltecV3,
.heltecWslV3,
.privateHw,
]
}
@ -2144,6 +2158,8 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding {
40: .same(proto: "NRF52840_PCA10059"),
41: .same(proto: "DR_DEV"),
42: .same(proto: "M5STACK"),
43: .same(proto: "HELTEC_V3"),
44: .same(proto: "HELTEC_WSL_V3"),
255: .same(proto: "PRIVATE_HW"),
]
}

View file

@ -68,6 +68,10 @@ enum TelemetrySensorType: SwiftProtobuf.Enum {
///
/// 6-Axis inertial measurement sensor
case qmi8658 // = 10
///
/// 3-Axis magnetic sensor
case qmc5883L // = 11
case UNRECOGNIZED(Int)
init() {
@ -87,6 +91,7 @@ enum TelemetrySensorType: SwiftProtobuf.Enum {
case 8: self = .lps22
case 9: self = .qmc6310
case 10: self = .qmi8658
case 11: self = .qmc5883L
default: self = .UNRECOGNIZED(rawValue)
}
}
@ -104,6 +109,7 @@ enum TelemetrySensorType: SwiftProtobuf.Enum {
case .lps22: return 8
case .qmc6310: return 9
case .qmi8658: return 10
case .qmc5883L: return 11
case .UNRECOGNIZED(let i): return i
}
}
@ -126,6 +132,7 @@ extension TelemetrySensorType: CaseIterable {
.lps22,
.qmc6310,
.qmi8658,
.qmc5883L,
]
}
@ -288,6 +295,7 @@ extension TelemetrySensorType: SwiftProtobuf._ProtoNameProviding {
8: .same(proto: "LPS22"),
9: .same(proto: "QMC6310"),
10: .same(proto: "QMI8658"),
11: .same(proto: "QMC5883L"),
]
}

View file

@ -29,9 +29,7 @@ struct Connect: View {
List {
if bleManager.isSwitchedOn {
Section(header: Text("Connected Radio").font(.title)) {
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected {
HStack {
Image(systemName: "antenna.radiowaves.left.and.right")
.symbolRenderingMode(.hierarchical)

View file

@ -11,12 +11,27 @@ 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)
#if targetEnvironment(macCatalyst)
VStack {
Image("logo-white")
.resizable()
.renderingMode(.template)
.foregroundColor(.accentColor)
.scaledToFit()
}
.padding(.bottom, 5)
.padding(.top, 5)
.offset(x: -15)
#else
VStack {
Image(colorScheme == .dark ? "logo-white" : "logo-black")
.resizable()
.renderingMode(.template)
.scaledToFit()
}
.padding(.bottom, 5)
.offset(x: -15)
#endif
}
}

View file

@ -13,7 +13,7 @@ struct MessageBubble: View {
HStack(alignment: .top) {
CircleText(text: shortName, color: isCurrentUser ? Color.blue : Color(.darkGray)).padding(.all, 5)
CircleText(text: shortName, color: isCurrentUser ? .accentColor : Color(.gray)).padding(.all, 5)
.gesture(LongPressGesture(minimumDuration: 2)
.onEnded {_ in
print("I want to delete message: \(id)")
@ -25,7 +25,7 @@ struct MessageBubble: View {
.textSelection(.enabled)
.padding(10)
.foregroundColor(.white)
.background(isCurrentUser ? Color.blue : Color(.darkGray))
.background(isCurrentUser ? .accentColor : Color(.gray))
.cornerRadius(10)
HStack(spacing: 4) {

View file

@ -41,7 +41,7 @@ struct ChannelMessageList: View {
if message.replyID > 0 {
let messageReply = channel.allPrivateMessages.first(where: { $0.messageId == message.replyID })
HStack {
Text(messageReply?.messagePayload ?? "EMPTY MESSAGE").foregroundColor(.blue).font(.caption2)
Text(messageReply?.messagePayload ?? "EMPTY MESSAGE").foregroundColor(.accentColor).font(.caption2)
.padding(10)
.overlay(
RoundedRectangle(cornerRadius: 18)
@ -49,14 +49,14 @@ struct ChannelMessageList: View {
)
Image(systemName: "arrowshape.turn.up.left.fill")
.symbolRenderingMode(.hierarchical)
.imageScale(.large).foregroundColor(.blue)
.imageScale(.large).foregroundColor(.accentColor)
.padding(.trailing)
}
}
HStack (alignment: .top) {
if currentUser { Spacer(minLength:50) }
if !currentUser {
CircleText(text: message.fromUser?.shortName ?? "????", color: currentUser ? .accentColor : Color(.darkGray), circleSize: 44, fontSize: 14)
CircleText(text: message.fromUser?.shortName ?? "????", color: currentUser ? .accentColor : Color(.gray), circleSize: 44, fontSize: 14)
.padding(.all, 5)
.offset(y: -5)
}
@ -64,7 +64,7 @@ struct ChannelMessageList: View {
Text(message.messagePayload ?? "EMPTY MESSAGE")
.padding(10)
.foregroundColor(.white)
.background(currentUser ? Color.blue : Color(.darkGray))
.background(currentUser ? .accentColor : Color(.gray))
.cornerRadius(15)
.contextMenu {
VStack{
@ -332,7 +332,7 @@ struct ChannelMessageList: View {
}
}
}) {
Image(systemName: "arrow.up.circle.fill").font(.largeTitle).foregroundColor(.blue)
Image(systemName: "arrow.up.circle.fill").font(.largeTitle).foregroundColor(.accentColor)
}
}
.padding(.all, 15)
@ -342,7 +342,7 @@ struct ChannelMessageList: View {
.toolbar {
ToolbarItem(placement: .principal) {
HStack {
CircleText(text: String(channel.index), color: .blue, circleSize: 44, fontSize: 30).fixedSize()
CircleText(text: String(channel.index), color: .accentColor, circleSize: 44, fontSize: 30).fixedSize()
Text(String(channel.name ?? "Unknown").camelCaseToWords()).font(.headline)
}
}

View file

@ -42,48 +42,48 @@ struct Contacts: View {
HStack {
VStack(alignment: .leading) {
HStack {
CircleText(text: String(channel.index), color: Color.blue, circleSize: 52, fontSize: 40)
CircleText(text: String(channel.index), color: .gray, circleSize: 52, fontSize: 40)
.padding(.trailing, 5)
VStack {
Text(String(channel.name ?? "Channel \(channel.index)").camelCaseToWords()).font(.headline)
}
.frame(maxWidth: .infinity, alignment: .leading)
if channel.allPrivateMessages.count > 0 {
VStack (alignment: .trailing) {
if lastMessageDay == currentDay {
Text(lastMessageTime, style: .time )
.font(.callout)
.foregroundColor(.gray)
} else if lastMessageDay == (currentDay - 1) {
Text("Yesterday")
.font(.callout)
.foregroundColor(.gray)
} else if lastMessageDay < (currentDay - 1) && lastMessageDay > (currentDay - 5) {
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
.font(.callout)
.foregroundColor(.gray)
} else if lastMessageDay < (currentDay - 1800) {
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
.font(.callout)
.foregroundColor(.gray)
HStack {
Text(String(channel.name ?? "Channel \(channel.index)").camelCaseToWords()).font(.headline)
Spacer()
if channel.allPrivateMessages.count > 0 {
VStack (alignment: .trailing) {
if lastMessageDay == currentDay {
Text(lastMessageTime, style: .time )
.font(.subheadline)
} else if lastMessageDay == (currentDay - 1) {
Text("Yesterday")
.font(.subheadline)
} else if lastMessageDay < (currentDay - 1) && lastMessageDay > (currentDay - 5) {
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
.font(.subheadline)
} else if lastMessageDay < (currentDay - 1800) {
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
.font(.subheadline)
}
}
.brightness(-0.20)
}
}
if channel.allPrivateMessages.count > 0 {
HStack(alignment: .top) {
Text("\(mostRecent != nil ? mostRecent!.messagePayload! : " ")")
.truncationMode(.tail)
.frame(maxWidth: .infinity, alignment: .leading)
.brightness(-0.20)
.font(.body)
}
}
}
}
if channel.allPrivateMessages.count > 0 {
HStack(alignment: .top) {
Text("\(mostRecent != nil ? mostRecent!.messagePayload! : " ")")
.truncationMode(.tail)
.foregroundColor(Color.gray)
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.frame(maxWidth: .infinity, maxHeight: 80, alignment: .leading)
}
}
.padding(.top, 10)
@ -99,44 +99,44 @@ struct Contacts: View {
let lastMessageDay = Calendar.current.dateComponents([.day], from: lastMessageTime).day ?? 0
let currentDay = Calendar.current.dateComponents([.day], from: Date()).day ?? 0
HStack {
VStack(alignment: .leading) {
VStack {
HStack {
CircleText(text: user.shortName ?? "???", color: Color.blue, circleSize: 52, fontSize: 16)
CircleText(text: user.shortName ?? "???", color: .gray, circleSize: 52, fontSize: 16)
.padding(.trailing, 5)
VStack {
Text(user.longName ?? "Unknown").font(.headline)
}
.frame(maxWidth: .infinity, alignment: .leading)
if user.messageList.count > 0 {
VStack (alignment: .trailing) {
if lastMessageDay == currentDay {
Text(lastMessageTime, style: .time )
.font(.callout)
.foregroundColor(.gray)
} else if lastMessageDay == (currentDay - 1) {
Text("Yesterday")
.font(.callout)
.foregroundColor(.gray)
} else if lastMessageDay < (currentDay - 1) && lastMessageDay > (currentDay - 5) {
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
.font(.callout)
.foregroundColor(.gray)
} else if lastMessageDay < (currentDay - 1800) {
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
.font(.callout)
.foregroundColor(.gray)
HStack {
Text(user.longName ?? "Unknown").font(.headline)
Spacer()
if user.messageList.count > 0 {
VStack (alignment: .trailing) {
if lastMessageDay == currentDay {
Text(lastMessageTime, style: .time )
.font(.subheadline)
} else if lastMessageDay == (currentDay - 1) {
Text("Yesterday")
.font(.subheadline)
} else if lastMessageDay < (currentDay - 1) && lastMessageDay > (currentDay - 5) {
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
.font(.subheadline)
} else if lastMessageDay < (currentDay - 1800) {
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
.font(.subheadline)
}
}
.brightness(-0.2)
}
}
if user.messageList.count > 0 {
HStack(alignment: .top) {
Text("\(mostRecent != nil ? mostRecent!.messagePayload! : " ")")
.truncationMode(.tail)
.font(.body)
.frame(maxWidth: .infinity, alignment: .leading)
.brightness(-0.2)
}
}
}
}
if user.messageList.count > 0 {
HStack(alignment: .top) {
Text("\(mostRecent != nil ? mostRecent!.messagePayload! : " ")")
.truncationMode(.tail)
.foregroundColor(Color.gray)
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(maxWidth: .infinity, maxHeight: 80, alignment: .leading)
}
}
}
@ -147,10 +147,7 @@ struct Contacts: View {
}
}
}
.tint(Color(UIColor.systemGray))
.navigationSplitViewStyle(.automatic)
.navigationTitle("Contacts")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(leading:
MeshtasticLogo()
)

View file

@ -42,7 +42,7 @@ struct UserMessageList: View {
if message.replyID > 0 {
let messageReply = user.messageList.first(where: { $0.messageId == message.replyID })
HStack {
Text(messageReply?.messagePayload ?? "EMPTY MESSAGE").foregroundColor(.blue).font(.caption2)
Text(messageReply?.messagePayload ?? "EMPTY MESSAGE").foregroundColor(.accentColor).font(.caption2)
.padding(10)
.overlay(
RoundedRectangle(cornerRadius: 18)
@ -50,14 +50,14 @@ struct UserMessageList: View {
)
Image(systemName: "arrowshape.turn.up.left.fill")
.symbolRenderingMode(.hierarchical)
.imageScale(.large).foregroundColor(.blue)
.imageScale(.large).foregroundColor(.accentColor)
.padding(.trailing)
}
}
HStack (alignment: .top) {
if currentUser { Spacer(minLength:50) }
if !currentUser {
CircleText(text: message.fromUser?.shortName ?? "????", color: currentUser ? .accentColor : Color(.darkGray), circleSize: 44, fontSize: 14)
CircleText(text: message.fromUser?.shortName ?? "????", color: currentUser ? .accentColor : Color(.gray), circleSize: 44, fontSize: 14)
.padding(.all, 5)
.offset(y: -5)
}
@ -65,7 +65,7 @@ struct UserMessageList: View {
Text(message.messagePayload ?? "EMPTY MESSAGE")
.padding(10)
.foregroundColor(.white)
.background(currentUser ? Color.blue : Color(.darkGray))
.background(currentUser ? .accentColor : Color(.gray))
.cornerRadius(15)
.contextMenu {
VStack{
@ -327,7 +327,7 @@ struct UserMessageList: View {
}
}
}) {
Image(systemName: "arrow.up.circle.fill").font(.largeTitle).foregroundColor(.blue)
Image(systemName: "arrow.up.circle.fill").font(.largeTitle).foregroundColor(.accentColor)
}
}
.padding(.all, 15)
@ -337,7 +337,7 @@ struct UserMessageList: View {
.toolbar {
ToolbarItem(placement: .principal) {
HStack {
CircleText(text: user.shortName ?? "???", color: .blue, circleSize: 44, fontSize: 14).fixedSize()
CircleText(text: user.shortName ?? "???", color: .accentColor, circleSize: 44, fontSize: 14).fixedSize()
Text(user.longName ?? "Unknown").font(.headline)
}
}

View file

@ -15,10 +15,8 @@ struct DeviceMetricsLog: View {
@EnvironmentObject var bleManager: BLEManager
@State private var isPresentingClearLogConfirm: Bool = false
@State var isExporting = false
@State var exportString = ""
var node: NodeInfoEntity
var body: some View {
@ -43,14 +41,10 @@ struct DeviceMetricsLog: View {
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
//Add a table for mac and ipad
Table(node.telemetries!.reversed() as! [TelemetryEntity]) {
TableColumn("Battery Level") { dm in
if dm.metricsType == 0 {
if dm.batteryLevel == 0 {
Text("Powered")
} else {
Text("\(String(dm.batteryLevel))%")
@ -80,7 +74,6 @@ struct DeviceMetricsLog: View {
}
} else {
ScrollView {
Grid(alignment: .topLeading, horizontalSpacing: 2) {
GridRow {
@ -129,13 +122,9 @@ struct DeviceMetricsLog: View {
}
}
HStack {
Button(role: .destructive) {
isPresentingClearLogConfirm = true
} label: {
Label("Clear Log", systemImage: "trash.fill")
}
.buttonStyle(.bordered)
@ -148,21 +137,16 @@ struct DeviceMetricsLog: View {
titleVisibility: .visible
) {
Button("Delete all device metrics?", role: .destructive) {
if clearTelemetry(destNum: node.num, metricsType: 0, context: context) {
print("Clear Device Metrics Log Failed")
print("Cleared Device Metrics for \(node.num)")
} else {
print("Clear Device Metrics Log Failed")
}
}
}
Button {
exportString = TelemetryToCsvFile(telemetry: node.telemetries!.array as! [TelemetryEntity], metricsType: 0)
isExporting = true
} label: {
Label("Save", systemImage: "square.and.arrow.down")
}
@ -171,17 +155,13 @@ struct DeviceMetricsLog: View {
.controlSize(.large)
.padding()
}
.navigationTitle("Device Metrics Log")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(trailing:
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
})
.onAppear {
self.bleManager.context = context
}
.fileExporter(
@ -190,14 +170,11 @@ struct DeviceMetricsLog: View {
contentType: .commaSeparatedText,
defaultFilename: String("\(node.user!.longName ?? "Node") Device Telemetry Log"),
onCompletion: { result in
if case .success = result {
print("Device Telemetry log download succeeded.")
self.isExporting = false
} else {
print("Device Telemetry log download failed: \(result).")
}
}

View file

@ -42,7 +42,7 @@ struct NodeList: View {
let connected: Bool = (bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.num == node.num)
VStack(alignment: .leading) {
HStack {
CircleText(text: node.user?.shortName ?? "???", color: .blue, circleSize: 52, fontSize: 16).offset(y: 1).padding(.trailing, 5)
CircleText(text: node.user?.shortName ?? "???", color: .gray, circleSize: 52, fontSize: 16).offset(y: 1).padding(.trailing, 5)
.offset(x: -15)
Text(node.user?.longName ?? "Unknown").font(.headline).offset(x: -15)
@ -50,9 +50,10 @@ struct NodeList: View {
.padding(.bottom, 5)
if connected {
HStack(alignment: .bottom) {
Image(systemName: "repeat.circle.fill").font(.title2)
.foregroundColor(.accentColor).symbolRenderingMode(.hierarchical)
Text("Currently Connected").font(.callout).foregroundColor(Color.accentColor)
Image(systemName: "repeat.circle.fill")
.font(.title2)
.symbolRenderingMode(.hierarchical)
Text("Currently Connected").font(.callout)
}
.padding(.bottom, 2)
}
@ -63,25 +64,27 @@ struct NodeList: View {
if lastPostion.coordinate != nil {
let nodeCoord = CLLocation(latitude: lastPostion.coordinate!.latitude, longitude: lastPostion.coordinate!.longitude)
let metersAway = nodeCoord.distance(from: myCoord)
Image(systemName: "lines.measurement.horizontal").font(.title3)
.foregroundColor(.accentColor).symbolRenderingMode(.hierarchical)
Image(systemName: "lines.measurement.horizontal")
.font(.title3)
.symbolRenderingMode(.hierarchical)
DistanceText(meters: metersAway).font(.subheadline).foregroundColor(.gray)
DistanceText(meters: metersAway).font(.subheadline)
}
}
.padding(.bottom, 2)
}
HStack(alignment: .bottom) {
Image(systemName: "clock.badge.checkmark.fill").font(.headline)
.foregroundColor(.accentColor).symbolRenderingMode(.hierarchical)
LastHeardText(lastHeard: node.lastHeard).font(.subheadline).foregroundColor(.gray)
Image(systemName: "clock.badge.checkmark.fill")
.font(.headline)
.symbolRenderingMode(.hierarchical)
LastHeardText(lastHeard: node.lastHeard)
.font(.subheadline)
}
}
.padding([.leading, .top, .bottom])
}
}
}
.tint(Color(UIColor.systemGray))
.navigationTitle("All Nodes")
.navigationBarItems(leading:
MeshtasticLogo()