Add favorite and distance filter to the node list

This commit is contained in:
Garth Vander Houwen 2024-04-02 06:17:03 -07:00
parent ee891f62c7
commit 78c0bca781
5 changed files with 62 additions and 39 deletions

View file

@ -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
}
}

View file

@ -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)
}
}

View file

@ -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<NodeInfoEntity>
@ -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])

View file

@ -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 {

View file

@ -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)
}
}