From 684997723949adc5e1f8ce56c21fa68e65d094c2 Mon Sep 17 00:00:00 2001 From: Austin Payne Date: Mon, 5 Feb 2024 09:28:47 -0700 Subject: [PATCH] feature: add simple retry mechanism --- Meshtastic.xcodeproj/project.pbxproj | 4 ++ .../Views/Messages/ChannelMessageList.swift | 5 ++ Meshtastic/Views/Messages/RetryButton.swift | 54 +++++++++++++++++++ .../Views/Messages/UserMessageList.swift | 5 ++ 4 files changed, 68 insertions(+) create mode 100644 Meshtastic/Views/Messages/RetryButton.swift diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index bf68cc37..9c0fc8fc 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 6DA39D8E2A92DC52007E311C /* MeshtasticAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */; }; 6DEDA55A2A957B8E00321D2E /* DetectionSensorLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */; }; 6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */; }; + B399E8A42B6F486400E4488E /* RetryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B399E8A32B6F486400E4488E /* RetryButton.swift */; }; B3E905B12B71F7F300654D07 /* TextMessageField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E905B02B71F7F300654D07 /* TextMessageField.swift */; }; C9697F9D279336B700250207 /* LocalMBTileOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9697F9C279336B700250207 /* LocalMBTileOverlay.swift */; }; C9697FA527933B8C00250207 /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = C9697FA427933B8C00250207 /* SQLite */; }; @@ -230,6 +231,7 @@ 6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectionSensorLog.swift; sourceTree = ""; }; 6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageEntityExtension.swift; sourceTree = ""; }; A65FA974296876BF00A97686 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; + B399E8A32B6F486400E4488E /* RetryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetryButton.swift; sourceTree = ""; }; B3E905B02B71F7F300654D07 /* TextMessageField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMessageField.swift; sourceTree = ""; }; C9697F9C279336B700250207 /* LocalMBTileOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalMBTileOverlay.swift; sourceTree = ""; }; D9C9839C2B79CFD700BDBE6A /* TextMessageSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMessageSize.swift; sourceTree = ""; }; @@ -843,6 +845,7 @@ DDB8F40F2A9EE5B400230ECE /* Messages.swift */, DDB8F4112A9EE5DD00230ECE /* UserList.swift */, DD1BF2F82776FE2E008C8D2F /* UserMessageList.swift */, + B399E8A32B6F486400E4488E /* RetryButton.swift */, ); path = Messages; sourceTree = ""; @@ -1197,6 +1200,7 @@ DDDB263F2AABEE20003AFCB7 /* NodeList.swift in Sources */, DDA0B6B2294CDC55001356EC /* Channels.swift in Sources */, DDE9659C2B1C3B6A00531070 /* RouteRecorder.swift in Sources */, + B399E8A42B6F486400E4488E /* RetryButton.swift in Sources */, DDB8F4102A9EE5B400230ECE /* Messages.swift in Sources */, DDDB26482AACD6D1003AFCB7 /* NodeMapMapkit.swift in Sources */, DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */, diff --git a/Meshtastic/Views/Messages/ChannelMessageList.swift b/Meshtastic/Views/Messages/ChannelMessageList.swift index e9f469d6..70369d0e 100644 --- a/Meshtastic/Views/Messages/ChannelMessageList.swift +++ b/Meshtastic/Views/Messages/ChannelMessageList.swift @@ -224,6 +224,11 @@ struct ChannelMessageList: View { } .padding(.bottom) .id(channel.allPrivateMessages.firstIndex(of: message)) + + if currentUser && message.ackError > 0 { + RetryButton(message: message) + } + if !currentUser { Spacer(minLength: 50) } diff --git a/Meshtastic/Views/Messages/RetryButton.swift b/Meshtastic/Views/Messages/RetryButton.swift new file mode 100644 index 00000000..116a31c1 --- /dev/null +++ b/Meshtastic/Views/Messages/RetryButton.swift @@ -0,0 +1,54 @@ +import SwiftUI + +struct RetryButton: View { + @Environment(\.managedObjectContext) var context + @EnvironmentObject var bleManager: BLEManager + + let message: MessageEntity + @State var isShowingConfirmation = false + + var body: some View { + Button { + isShowingConfirmation = true + } label: { + Image(systemName: "exclamationmark.circle") + .foregroundColor(.gray) + .frame(height: 30) + .padding(.top, 5) + } + .confirmationDialog( + "This message was likely not delivered.", + isPresented: $isShowingConfirmation, + titleVisibility: .visible + ) { + Button("Try Again") { + guard bleManager.connectedPeripheral?.peripheral.state == .connected else { + return + } + let messageID = message.messageId + let payload = message.messagePayload ?? "" + let userNum = message.toUser?.num ?? 0 + let channel = message.channel + let isEmoji = message.isEmoji + let replyID = message.replyID + context.delete(message) + do { + try context.save() + } catch { + print("Failed to delete message \(messageID)") + } + if !bleManager.sendMessage( + message: payload, + toUserNum: userNum, + channel: channel, + isEmoji: isEmoji, + replyID: replyID + ) { + // Best effort, unlikely since we already checked BLE state + print("Failed to resend message \(messageID)") + } + } + Button("Cancel", role: .cancel) {} + } + } +} diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index 0e63090d..387abaf8 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -202,6 +202,11 @@ struct UserMessageList: View { } .padding(.bottom) .id(user.messageList.firstIndex(of: message)) + + if currentUser && message.ackError > 0 { + RetryButton(message: message) + } + if !currentUser { Spacer(minLength: 50) }