Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add node actions to the node detail screen #761

Merged
merged 5 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@
},
"Acknowledged by another node" : {

},
"Actions" : {

},
"Active" : {

Expand Down Expand Up @@ -400,6 +403,9 @@
},
"Add Channels" : {

},
"Add to favorites" : {

},
"Additional help" : {

Expand Down Expand Up @@ -8201,6 +8207,9 @@
},
"Help with App Development" : {

},
"Hide alerts" : {

},
"Hide Alerts" : {

Expand Down Expand Up @@ -17150,6 +17159,9 @@
},
"Remove" : {

},
"Remove from favorites" : {

},
"Replace Channels" : {

Expand Down Expand Up @@ -19618,6 +19630,9 @@
},
"Short Name: %@" : {

},
"Show alerts" : {

},
"Show Alerts" : {

Expand Down Expand Up @@ -20860,7 +20875,7 @@
"This conversation will be deleted." : {

},
"This could take a while, response will appear in the trace route log for the node it was sent to." : {
"This could take a while. The response will appear in the trace route log for the node it was sent to." : {

},
"This determines the actual frequency you are transmitting on in the band. If set to 0 this value will be calculated automatically based on the primary channel name." : {
Expand Down
32 changes: 32 additions & 0 deletions Meshtastic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
objects = {

/* Begin PBXBuildFile section */
251926852C3BA97800249DF5 /* FavoriteNodeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 251926842C3BA97800249DF5 /* FavoriteNodeButton.swift */; };
251926872C3BAE2200249DF5 /* NodeAlertsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 251926862C3BAE2200249DF5 /* NodeAlertsButton.swift */; };
2519268A2C3BB1B200249DF5 /* ExchangePositionsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 251926892C3BB1B200249DF5 /* ExchangePositionsButton.swift */; };
2519268C2C3BB52000249DF5 /* TraceRouteButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2519268B2C3BB52000249DF5 /* TraceRouteButton.swift */; };
251926902C3CB44900249DF5 /* ClientHistoryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2519268F2C3CB44900249DF5 /* ClientHistoryButton.swift */; };
251926922C3CB52300249DF5 /* DeleteNodeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 251926912C3CB52300249DF5 /* DeleteNodeButton.swift */; };
259792252C2F114500AD1659 /* ChannelEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD58C5F12919AD3C00D5BEFB /* ChannelEntityExtension.swift */; };
259792262C2F114500AD1659 /* PositionEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */; };
259792272C2F114500AD1659 /* TraceRouteEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE5B4052B227E3200FCDD05 /* TraceRouteEntityExtension.swift */; };
Expand Down Expand Up @@ -222,6 +228,12 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
251926842C3BA97800249DF5 /* FavoriteNodeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteNodeButton.swift; sourceTree = "<group>"; };
251926862C3BAE2200249DF5 /* NodeAlertsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeAlertsButton.swift; sourceTree = "<group>"; };
251926892C3BB1B200249DF5 /* ExchangePositionsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExchangePositionsButton.swift; sourceTree = "<group>"; };
2519268B2C3BB52000249DF5 /* TraceRouteButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TraceRouteButton.swift; sourceTree = "<group>"; };
2519268F2C3CB44900249DF5 /* ClientHistoryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientHistoryButton.swift; sourceTree = "<group>"; };
251926912C3CB52300249DF5 /* DeleteNodeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteNodeButton.swift; sourceTree = "<group>"; };
25AECD4E2C2F723200862C8E /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
6D825E612C34786C008DBEE4 /* CommonRegex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonRegex.swift; sourceTree = "<group>"; };
6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticAppDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -471,6 +483,19 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
251926882C3BAF2E00249DF5 /* Actions */ = {
isa = PBXGroup;
children = (
251926842C3BA97800249DF5 /* FavoriteNodeButton.swift */,
251926892C3BB1B200249DF5 /* ExchangePositionsButton.swift */,
251926862C3BAE2200249DF5 /* NodeAlertsButton.swift */,
2519268B2C3BB52000249DF5 /* TraceRouteButton.swift */,
2519268F2C3CB44900249DF5 /* ClientHistoryButton.swift */,
251926912C3CB52300249DF5 /* DeleteNodeButton.swift */,
);
path = Actions;
sourceTree = "<group>";
};
C9483F6B2773016700998F6B /* MapKitMap */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -874,6 +899,7 @@
DDDB26452AACC0B7003AFCB7 /* NodeInfoItem.swift */,
DDDB26412AABF655003AFCB7 /* NodeListItem.swift */,
DDDCD56F2BB26F5C00BE6B60 /* NodeListFilter.swift */,
251926882C3BAF2E00249DF5 /* Actions */,
);
path = Helpers;
sourceTree = "<group>";
Expand Down Expand Up @@ -1112,6 +1138,7 @@
DD93800E2BA74D0C008BEC06 /* ChannelForm.swift in Sources */,
DD41A61529AB0035003C5A37 /* NodeWeatherForecast.swift in Sources */,
DDB6ABD628AE742000384BA1 /* BluetoothConfig.swift in Sources */,
251926902C3CB44900249DF5 /* ClientHistoryButton.swift in Sources */,
DDD5BB102C285FB3007E03CA /* AppLogFilter.swift in Sources */,
DD4640202AFF10F4002A5ECB /* WaypointForm.swift in Sources */,
DD769E0328D18BF1001A3F05 /* DeviceMetricsLog.swift in Sources */,
Expand Down Expand Up @@ -1168,6 +1195,7 @@
DD007BB02AA5981000F5FA12 /* NodeInfoEntityExtension.swift in Sources */,
DDDB26422AABF655003AFCB7 /* NodeListItem.swift in Sources */,
DDDB444629F8A96500EE2349 /* Character.swift in Sources */,
2519268C2C3BB52000249DF5 /* TraceRouteButton.swift in Sources */,
DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */,
DDB6ABDB28B0AC6000384BA1 /* DistanceText.swift in Sources */,
DD94B7402ACCE3BE00DCD1D1 /* MapSettingsForm.swift in Sources */,
Expand All @@ -1188,6 +1216,7 @@
DDB6ABE028B13AC700384BA1 /* DeviceEnums.swift in Sources */,
DD86D40C287F401000BAEB7A /* SaveChannelQRCode.swift in Sources */,
D93068DD2B81CA820066FBC8 /* ConfigHeader.swift in Sources */,
251926872C3BAE2200249DF5 /* NodeAlertsButton.swift in Sources */,
DDA1C48E28DB49D3009933EC /* ChannelRoles.swift in Sources */,
D9BC22DB2B7DE8E2006A37D5 /* TileDownloadStatus.swift in Sources */,
DDD5BB092C285DDC007E03CA /* AppLog.swift in Sources */,
Expand All @@ -1202,6 +1231,7 @@
DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */,
DDDE5A1029AFE69700490C6C /* MeshActivityAttributes.swift in Sources */,
DD1925B928CDA93900720036 /* SerialConfigEnums.swift in Sources */,
251926852C3BA97800249DF5 /* FavoriteNodeButton.swift in Sources */,
D9C983A02B79D0E800BDBE6A /* AlertButton.swift in Sources */,
DD86D4112881D16900BAEB7A /* WriteCsvFile.swift in Sources */,
DDDB445029F8AC9C00EE2349 /* UIImage.swift in Sources */,
Expand All @@ -1213,9 +1243,11 @@
DDB75A212A12B954006ED576 /* LoRaSignalStrength.swift in Sources */,
DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */,
DD268D8E2BCC90E2008073AE /* RouteEnums.swift in Sources */,
251926922C3CB52300249DF5 /* DeleteNodeButton.swift in Sources */,
DDB6ABE428B13FFF00384BA1 /* DisplayEnums.swift in Sources */,
DD4975A52B147BA90026544E /* AmbientLightingConfig.swift in Sources */,
D93068D92B81509C0066FBC8 /* TapbackResponses.swift in Sources */,
2519268A2C3BB1B200249DF5 /* ExchangePositionsButton.swift in Sources */,
DD86D40A287F04F100BAEB7A /* InvalidVersion.swift in Sources */,
DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */,
DDB6ABE228B13FB500384BA1 /* PositionConfigEnums.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "74b3ad6215f078d89f4436b6ce0e318f145842efa3453bbe055ab76057de7d6b",
"originHash" : "c5be9820b6e5add3da0e3bd134c3826b3eece5f926d667cb3800a26572f9e63c",
"pins" : [
{
"identity" : "cocoamqtt",
Expand Down
33 changes: 33 additions & 0 deletions Meshtastic/Views/Nodes/Helpers/Actions/ClientHistoryButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import SwiftUI

struct ClientHistoryButton: View {
var bleManager: BLEManager

var connectedNode: NodeInfoEntity

var node: NodeInfoEntity

@State
private var isPresentingAlert = false

var body: some View {
Button {
isPresentingAlert = bleManager.requestStoreAndForwardClientHistory(
fromUser: connectedNode.user!,
toUser: node.user!
)
} label: {
Label(
"Client History",
systemImage: "envelope.arrow.triangle.branch"
)
}.alert(
"Client History Request Sent",
isPresented: $isPresentingAlert
) {
Button("OK") { }.keyboardShortcut(.defaultAction)
} message: {
Text("Any missed messages will be delivered again.")
}
}
}
51 changes: 51 additions & 0 deletions Meshtastic/Views/Nodes/Helpers/Actions/DeleteNodeButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import CoreData
import OSLog
import SwiftUI

struct DeleteNodeButton: View {
var bleManager: BLEManager

var context: NSManagedObjectContext

var connectedNode: NodeInfoEntity

var node: NodeInfoEntity

@State
private var isPresentingAlert = false

var body: some View {
Button(role: .destructive) {
isPresentingAlert = true
} label: {
Label {
Text("Delete Node")
} icon: {
Image(systemName: "trash")
.symbolRenderingMode(.multicolor)
}
}
.confirmationDialog(
"are.you.sure",
isPresented: $isPresentingAlert,
titleVisibility: .visible
) {
Button("Delete Node", role: .destructive) {
guard let deleteNode = getNodeInfo(
id: node.num,
context: context
) else {
Logger.data.error("Unable to find node info to delete node \(node.num)")
return
}
let success = bleManager.removeNode(
node: deleteNode,
connectedNodeNum: connectedNode.num
)
if !success {
Logger.data.error("Failed to delete node \(deleteNode.user?.longName ?? "unknown".localized)")
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import CoreData
import SwiftUI

struct ExchangePositionsButton: View {
var bleManager: BLEManager

var node: NodeInfoEntity

@State
private var isPresentingPositionSentAlert: Bool = false

var body: some View {
Button {
isPresentingPositionSentAlert = bleManager.sendPosition(
channel: node.channel,
destNum: node.num,
wantResponse: true
)
} label: {
Label {
Text("Exchange Positions")
} icon: {
Image(systemName: "arrow.triangle.2.circlepath")
.symbolRenderingMode(.hierarchical)
}
}.alert(
"Position Sent",
isPresented: $isPresentingPositionSentAlert
) {
Button("OK") { }.keyboardShortcut(.defaultAction)
} message: {
Text("Your position has been sent with a request for a response with their position.")
}
}
}
45 changes: 45 additions & 0 deletions Meshtastic/Views/Nodes/Helpers/Actions/FavoriteNodeButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import CoreData
import OSLog
import SwiftUI

struct FavoriteNodeButton: View {
var bleManager: BLEManager
var context: NSManagedObjectContext

@ObservedObject
var node: NodeInfoEntity

var body: some View {
Button {
guard let connectedNodeNum = bleManager.connectedPeripheral?.num else { return }
let success = if node.favorite {
bleManager.removeFavoriteNode(
node: node,
connectedNodeNum: Int64(connectedNodeNum)
)
} else {
bleManager.setFavoriteNode(
node: node,
connectedNodeNum: Int64(connectedNodeNum)
)
}
if success {
node.favorite = !node.favorite
do {
try context.save()
} catch {
context.rollback()
Logger.data.error("Save Node Favorite Error")
}
Logger.data.debug("Favorited a node")
}
} label: {
Label {
Text(node.favorite ? "Remove from favorites" : "Add to favorites")
} icon: {
Image(systemName: node.favorite ? "star.fill" : "star")
.symbolRenderingMode(.multicolor)
}
}
}
}
33 changes: 33 additions & 0 deletions Meshtastic/Views/Nodes/Helpers/Actions/NodeAlertsButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import CoreData
import OSLog
import SwiftUI

struct NodeAlertsButton: View {
var context: NSManagedObjectContext

@ObservedObject
var node: NodeInfoEntity

@ObservedObject
var user: UserEntity

var body: some View {
Button {
user.mute = !user.mute
context.refresh(node, mergeChanges: true)
do {
try context.save()
} catch {
context.rollback()
Logger.data.error("Save User Mute Error")
}
} label: {
Label {
Text(user.mute ? "Show alerts" : "Hide alerts")
} icon: {
Image(systemName: user.mute ? "bell.slash" : "bell")
.symbolRenderingMode(.hierarchical)
}
}
}
}
33 changes: 33 additions & 0 deletions Meshtastic/Views/Nodes/Helpers/Actions/TraceRouteButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import SwiftUI

struct TraceRouteButton: View {
var bleManager: BLEManager

var node: NodeInfoEntity

@State
private var isPresentingTraceRouteSentAlert: Bool = false

var body: some View {
Button {
isPresentingTraceRouteSentAlert = bleManager.sendTraceRouteRequest(
destNum: node.user?.num ?? 0,
wantResponse: true
)
} label: {
Label {
Text("Trace Route")
} icon: {
Image(systemName: "signpost.right.and.left")
.symbolRenderingMode(.hierarchical)
}
}.alert(
"Trace Route Sent",
isPresented: $isPresentingTraceRouteSentAlert
) {
Button("OK") { }.keyboardShortcut(.defaultAction)
} message: {
Text("This could take a while. The response will appear in the trace route log for the node it was sent to.")
}
}
}
Loading