diff --git a/Meshtastic/Extensions/CoreData/MyInfoEntityExtension.swift b/Meshtastic/Extensions/CoreData/MyInfoEntityExtension.swift index 1e04282a..a9e22a39 100644 --- a/Meshtastic/Extensions/CoreData/MyInfoEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/MyInfoEntityExtension.swift @@ -14,7 +14,7 @@ extension MyInfoEntity { } var unreadMessages: Int { - let unreadMessages = messageList.filter{ ($0 as AnyObject).read == false } + let unreadMessages = messageList.filter{ ($0 as AnyObject).read == false && ($0 as AnyObject).isEmoji == false } return unreadMessages.count } } diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift b/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift index 79574927..6726c90b 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift @@ -14,6 +14,7 @@ struct NodeListFilter: View { @Binding var viaLora: Bool @Binding var viaMqtt: Bool @Binding var isOnline: Bool + @Binding var isFavorite: Bool @Binding var distanceFilter: Bool @Binding var maximumDistance: Double @Binding var hopsAway: Int @@ -48,7 +49,7 @@ struct NodeListFilter: View { Toggle(isOn: $isOnline) { Label { - Text("Online Only") + Text("Online") } icon: { Image(systemName: "checkmark.circle.fill") .foregroundColor(.green) @@ -58,29 +59,43 @@ struct NodeListFilter: View { .toggleStyle(SwitchToggleStyle(tint: .accentColor)) .listRowSeparator(.visible) -// Toggle(isOn: $distanceFilter) { -// -// Label { -// Text("Distance") -// } icon: { -// Image(systemName: "map") -// } -// } -// .toggleStyle(SwitchToggleStyle(tint: .accentColor)) -// -// .listRowSeparator(distanceFilter ? .hidden : .visible) -// if distanceFilter { -// HStack { -// Label("Show nodes", systemImage: "lines.measurement.horizontal") -// Picker("", selection: $maximumDistance) { -// ForEach(MeshMapDistances.allCases) { di in -// Text(di.description) -// .tag(di.id) -// } -// } -// .pickerStyle(DefaultPickerStyle()) -// } -// } + Toggle(isOn: $isFavorite) { + + Label { + Text("Favorites") + } icon: { + + Image(systemName: "star.fill") + .foregroundColor(.yellow) + .symbolRenderingMode(.hierarchical) + } + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + .listRowSeparator(.visible) + + Toggle(isOn: $distanceFilter) { + + Label { + Text("Distance") + } icon: { + Image(systemName: "map") + } + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + + .listRowSeparator(distanceFilter ? .hidden : .visible) + if distanceFilter { + HStack { + Label("Show nodes", systemImage: "lines.measurement.horizontal") + Picker("", selection: $maximumDistance) { + ForEach(MeshMapDistances.allCases) { di in + Text(di.description) + .tag(di.id) + } + } + .pickerStyle(DefaultPickerStyle()) + } + } HStack { Label("Hops Away", systemImage: "hare") Picker("", selection: $hopsAway) { @@ -125,7 +140,7 @@ struct NodeListFilter: View { .padding(.bottom) #endif } - .presentationDetents([.fraction(0.40), .fraction(0.50)]) + .presentationDetents([.fraction(0.6), .fraction(0.75)]) .presentationDragIndicator(.visible) } } diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 1dfec72d..8ecb1df8 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -20,6 +20,7 @@ struct NodeList: View { @State private var viaLora = true @State private var viaMqtt = true @State private var isOnline = false + @State private var isFavorite = false @State private var distanceFilter = false @State private var maxDistance: Double = 800000 @State private var hopsAway: Int = -1 @@ -33,7 +34,9 @@ struct NodeList: View { @EnvironmentObject var bleManager: BLEManager @FetchRequest( - sortDescriptors: [NSSortDescriptor(key: "favorite", ascending: false), NSSortDescriptor(key: "lastHeard", ascending: false)], + sortDescriptors: [NSSortDescriptor(key: "favorite", ascending: false), + NSSortDescriptor(key: "lastHeard", ascending: false), + NSSortDescriptor(key: "user.longName", ascending: true)], animation: .default) var nodes: FetchedResults @@ -164,7 +167,7 @@ struct NodeList: View { } } .sheet(isPresented: $isEditingFilters) { - NodeListFilter(viaLora: $viaLora, viaMqtt: $viaMqtt, isOnline: $isOnline, distanceFilter: $distanceFilter, maximumDistance: $maxDistance, hopsAway: $hopsAway, deviceRole: $deviceRole) + NodeListFilter(viaLora: $viaLora, viaMqtt: $viaMqtt, isOnline: $isOnline, isFavorite: $isFavorite, distanceFilter: $distanceFilter, maximumDistance: $maxDistance, hopsAway: $hopsAway, deviceRole: $deviceRole) } .safeAreaInset(edge: .bottom, alignment: .trailing) { HStack { @@ -282,6 +285,12 @@ struct NodeList: View { .onChange(of: isOnline) { _ in searchNodeList() } + .onChange(of: isFavorite) { _ in + searchNodeList() + } + .onChange(of: maxDistance) { _ in + searchNodeList() + } .onAppear { if self.bleManager.context == nil { self.bleManager.context = context @@ -325,6 +334,11 @@ struct NodeList: View { let isOnlinePredicate = NSPredicate(format: "lastHeard >= %@", Calendar.current.date(byAdding: .minute, value: -15, to: Date())! as NSDate) predicates.append(isOnlinePredicate) } + /// Favorites + if isFavorite { + let isFavoritePredicate = NSPredicate(format: "favorite == YES") + predicates.append(isFavoritePredicate) + } /// Distance if distanceFilter { let pointOfInterest = LocationHelper.currentLocation @@ -339,15 +353,12 @@ struct NodeList: View { let maxLatitude: Double = pointOfInterest.latitude + deltaLatitude let minLongitude: Double = pointOfInterest.longitude - deltaLongitude let maxLongitude: Double = pointOfInterest.longitude + deltaLongitude - let distancePredicate = NSPredicate(format: "(%lf <= (positions[first].longitudeI / 1e7))", minLongitude, maxLongitude,minLatitude, maxLatitude) - //let distancePredicate = NSPredicate(format: "(%lf <= (positions[LAST].longitudeI / 1e7)) AND ((positions[LAST].longitudeI / 1e7) <= %lf) AND (%lf <= (positions[LAST].latitudeI / 1e7)) AND ((positions[LAST].latitudeI / 1e7) <= %lf)", minLongitude, maxLongitude,minLatitude, maxLatitude) - - //predicates.append(distancePredicate) + let distancePredicate = NSPredicate(format: "(SUBQUERY(positions, $position, $position.latest == TRUE && (%lf <= ($position.longitudeI / 1e7)) AND (($position.longitudeI / 1e7) <= %lf) AND (%lf <= ($position.latitudeI / 1e7)) AND (($position.latitudeI / 1e7) <= %lf))).@count > 0", minLongitude, maxLongitude,minLatitude, maxLatitude) + predicates.append(distancePredicate) } } if predicates.count > 0 || !searchText.isEmpty { - if !searchText.isEmpty { let filterPredicates = NSCompoundPredicate(type: .and, subpredicates: predicates) nodes.nsPredicate = NSCompoundPredicate(type: .and, subpredicates: [textSearchPredicate, filterPredicates]) diff --git a/Meshtastic/Views/Settings/Channels.swift b/Meshtastic/Views/Settings/Channels.swift index 8dfddfd2..d2bd8cf5 100644 --- a/Meshtastic/Views/Settings/Channels.swift +++ b/Meshtastic/Views/Settings/Channels.swift @@ -134,6 +134,8 @@ struct Channels: View { .padding() #endif ChannelForm(channelIndex: $channelIndex, channelName: $channelName, channelKeySize: $channelKeySize, channelKey: $channelKey, channelRole: $channelRole, uplink: $uplink, downlink: $downlink, positionPrecision: $positionPrecision, preciseLocation: $preciseLocation, positionsEnabled: $positionsEnabled, hasChanges: $hasChanges, hasValidKey: $hasValidKey, supportedVersion: $supportedVersion) + .presentationDetents([.large]) + .presentationDragIndicator(.visible) .onAppear { supportedVersion = bleManager.connectedVersion == "0.0.0" || self.minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedSame } @@ -149,8 +151,6 @@ struct Channels: View { channel.settings.uplinkEnabled = uplink channel.settings.downlinkEnabled = downlink channel.settings.moduleSettings.positionPrecision = UInt32(positionPrecision) - - guard let mutableChannels = node?.myInfo?.channels?.mutableCopy() as? NSMutableOrderedSet else { return @@ -221,8 +221,6 @@ struct Channels: View { .padding(.bottom) #endif } - .presentationDetents([.fraction(0.85), .large]) - .presentationDragIndicator(.visible) } if node?.myInfo?.channels?.array.count ?? 0 < 8 && node != nil { diff --git a/Meshtastic/Views/Settings/Channels/ChannelForm.swift b/Meshtastic/Views/Settings/Channels/ChannelForm.swift index da6127df..09238d49 100644 --- a/Meshtastic/Views/Settings/Channels/ChannelForm.swift +++ b/Meshtastic/Views/Settings/Channels/ChannelForm.swift @@ -105,6 +105,7 @@ struct ChannelForm: View { ) .onChange(of: channelKey, perform: { _ in + let tempKey = Data(base64Encoded: channelKey) ?? Data() if tempKey.count == channelKeySize || channelKeySize == -1{ hasValidKey = true @@ -245,7 +246,5 @@ struct ChannelForm: View { } } } - .presentationDetents([.large]) - .presentationDragIndicator(.visible) } }