mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Merge pull request #1191 from meshtastic/DisconnectSwipe
Disconnect swipe
This commit is contained in:
commit
45f7aedbbb
6 changed files with 121 additions and 16 deletions
|
|
@ -9665,6 +9665,12 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Disconnect Node" : {
|
||||
|
||||
},
|
||||
"Disconnect the currently connected node" : {
|
||||
|
||||
},
|
||||
"Dismiss" : {
|
||||
"localizations" : {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@
|
|||
BCB613832C672A2600485544 /* MessageChannelIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613822C672A2600485544 /* MessageChannelIntent.swift */; };
|
||||
BCB613852C68703800485544 /* NodePositionIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613842C68703800485544 /* NodePositionIntent.swift */; };
|
||||
BCB613872C69A0FB00485544 /* AppIntentErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613862C69A0FB00485544 /* AppIntentErrors.swift */; };
|
||||
BCDDFA9A2DBB180D0065189C /* ScrollToBottomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCDDFA992DBB180D0065189C /* ScrollToBottomButton.swift */; };
|
||||
BCD93CBA2D9E11A2006C9214 /* DisconnectNodeIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD93CB92D9E11A2006C9214 /* DisconnectNodeIntent.swift */; };
|
||||
BCDDFA9A2DBB180D0065189C /* ScrollToBottomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCDDFA992DBB180D0065189C /* ScrollToBottomButton.swift */; };
|
||||
BCE2D3C32C7ADF42008E6199 /* ShutDownNodeIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2D3C22C7ADF42008E6199 /* ShutDownNodeIntent.swift */; };
|
||||
BCE2D3C52C7AE369008E6199 /* RestartNodeIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2D3C42C7AE369008E6199 /* RestartNodeIntent.swift */; };
|
||||
BCE2D3C72C7B0D0A008E6199 /* ShortcutsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCE2D3C62C7B0D0A008E6199 /* ShortcutsProvider.swift */; };
|
||||
|
|
@ -331,7 +332,8 @@
|
|||
BCB613822C672A2600485544 /* MessageChannelIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageChannelIntent.swift; sourceTree = "<group>"; };
|
||||
BCB613842C68703800485544 /* NodePositionIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodePositionIntent.swift; sourceTree = "<group>"; };
|
||||
BCB613862C69A0FB00485544 /* AppIntentErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntentErrors.swift; sourceTree = "<group>"; };
|
||||
BCDDFA992DBB180D0065189C /* ScrollToBottomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollToBottomButton.swift; sourceTree = "<group>"; };
|
||||
BCD93CB92D9E11A2006C9214 /* DisconnectNodeIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisconnectNodeIntent.swift; sourceTree = "<group>"; };
|
||||
BCDDFA992DBB180D0065189C /* ScrollToBottomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollToBottomButton.swift; sourceTree = "<group>"; };
|
||||
BCE2D3C22C7ADF42008E6199 /* ShutDownNodeIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShutDownNodeIntent.swift; sourceTree = "<group>"; };
|
||||
BCE2D3C42C7AE369008E6199 /* RestartNodeIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestartNodeIntent.swift; sourceTree = "<group>"; };
|
||||
BCE2D3C62C7B0D0A008E6199 /* ShortcutsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsProvider.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -691,6 +693,7 @@
|
|||
BCE2D3C62C7B0D0A008E6199 /* ShortcutsProvider.swift */,
|
||||
BC6B45FE2CB2F98900723CEB /* SaveChannelSettingsIntent.swift */,
|
||||
BC47C2EE2CE0017D008245CA /* MessageNodeIntent.swift */,
|
||||
BCD93CB92D9E11A2006C9214 /* DisconnectNodeIntent.swift */,
|
||||
);
|
||||
path = AppIntents;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1418,6 +1421,7 @@
|
|||
DDC94FCE29CF55310082EA6E /* RtttlConfig.swift in Sources */,
|
||||
DD964FBD296E6B01007C176F /* EmojiOnlyTextField.swift in Sources */,
|
||||
DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */,
|
||||
BCD93CBA2D9E11A2006C9214 /* DisconnectNodeIntent.swift in Sources */,
|
||||
DDC94FC129CE063B0082EA6E /* BatteryLevel.swift in Sources */,
|
||||
231B3F252D087C3C0069A07D /* EnvironmentDefaultColumns.swift in Sources */,
|
||||
25F5D5BE2C3F6D87008036E3 /* NavigationState.swift in Sources */,
|
||||
|
|
|
|||
31
Meshtastic/AppIntents/DisconnectNodeIntent.swift
Normal file
31
Meshtastic/AppIntents/DisconnectNodeIntent.swift
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// DisconnectNodeIntent.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Created by Benjamin Faershtein on 4/2/25.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AppIntents
|
||||
|
||||
struct DisconnectNodeIntent: AppIntent {
|
||||
static var title: LocalizedStringResource = "Disconnect Node"
|
||||
|
||||
static var description: IntentDescription = "Disconnect the currently connected node"
|
||||
|
||||
|
||||
func perform() async throws -> some IntentResult {
|
||||
if !BLEManager.shared.isConnected {
|
||||
throw AppIntentErrors.AppIntentError.notConnected
|
||||
}
|
||||
|
||||
if let connectedPeripheral = BLEManager.shared.connectedPeripheral,
|
||||
connectedPeripheral.peripheral.state == .connected {
|
||||
BLEManager.shared.disconnectPeripheral(reconnect: false)
|
||||
} else {
|
||||
throw AppIntentErrors.AppIntentError.message("Error disconnecting node")
|
||||
}
|
||||
|
||||
return .result()
|
||||
}
|
||||
}
|
||||
|
|
@ -32,5 +32,13 @@ struct ShortcutsProvider: AppShortcutsProvider {
|
|||
"Send a \(.applicationName) group message"],
|
||||
shortTitle: "Group Message",
|
||||
systemImageName: "message")
|
||||
|
||||
AppShortcut(intent: DisconnectNodeIntent(),
|
||||
phrases: ["Disconnect \(.applicationName) node",
|
||||
"Disconnect my \(.applicationName) node",
|
||||
"Disconnect from \(.applicationName)",
|
||||
"Disconnect \(.applicationName)"],
|
||||
shortTitle: "Disconnect",
|
||||
systemImageName: "antenna.radiowaves.left.and.right.slash")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,20 +177,25 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
|
||||
// Disconnect Connected Peripheral
|
||||
func disconnectPeripheral(reconnect: Bool = true) {
|
||||
|
||||
guard let connectedPeripheral = connectedPeripheral else { return }
|
||||
if mqttProxyConnected {
|
||||
mqttManager.mqttClientProxy?.disconnect()
|
||||
// Ensure all operations run on the main thread
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
guard let connectedPeripheral = self.connectedPeripheral else { return }
|
||||
|
||||
if self.mqttProxyConnected {
|
||||
self.mqttManager.mqttClientProxy?.disconnect()
|
||||
}
|
||||
|
||||
self.automaticallyReconnect = reconnect
|
||||
self.centralManager?.cancelPeripheralConnection(connectedPeripheral.peripheral)
|
||||
self.FROMRADIO_characteristic = nil
|
||||
self.isConnected = false
|
||||
self.isSubscribed = false
|
||||
self.invalidVersion = false
|
||||
self.connectedVersion = "0.0.0"
|
||||
self.stopScanning()
|
||||
self.startScanning()
|
||||
}
|
||||
automaticallyReconnect = reconnect
|
||||
centralManager?.cancelPeripheralConnection(connectedPeripheral.peripheral)
|
||||
FROMRADIO_characteristic = nil
|
||||
isConnected = false
|
||||
isSubscribed = false
|
||||
invalidVersion = false
|
||||
connectedVersion = "0.0.0"
|
||||
stopScanning()
|
||||
startScanning()
|
||||
}
|
||||
|
||||
// Called each time a peripheral is connected
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ struct Connect: View {
|
|||
@State var liveActivityStarted = false
|
||||
@State var presentingSwitchPreferredPeripheral = false
|
||||
@State var selectedPeripherialId = ""
|
||||
@State private var showSwipeDemo = false
|
||||
@State private var swipeDemoOffset: CGFloat = 0
|
||||
@State private var showDeleteButton: Bool = false
|
||||
@AppStorage("hasSeenSwipeDemo") private var hasSeenSwipeDemo = false
|
||||
|
||||
init () {
|
||||
let notificationCenter = UNUserNotificationCenter.current()
|
||||
|
|
@ -89,6 +93,28 @@ struct Connect: View {
|
|||
.font(.caption)
|
||||
.foregroundColor(Color.gray)
|
||||
.padding([.top])
|
||||
.offset(x: swipeDemoOffset)
|
||||
.overlay(
|
||||
GeometryReader { geometry in
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.foregroundColor(.red)
|
||||
.frame(width: 80)
|
||||
.offset(x: geometry.size.width - 80)
|
||||
VStack {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right.slash")
|
||||
.foregroundColor(.white)
|
||||
.font(.title3)
|
||||
Text("Disconnect")
|
||||
.foregroundColor(.white)
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
.offset(x: geometry.size.width - 50)
|
||||
|
||||
.opacity(showDeleteButton ? 1 : 0)
|
||||
}
|
||||
)
|
||||
.swipeActions {
|
||||
Button(role: .destructive) {
|
||||
if let connectedPeripheral = bleManager.connectedPeripheral,
|
||||
|
|
@ -123,7 +149,15 @@ struct Connect: View {
|
|||
Text("Short Name: \(node?.user?.shortName ?? "?")")
|
||||
Text("Long Name: \(node?.user?.longName?.addingVariationSelectors ?? "Unknown".localized)")
|
||||
Text("BLE RSSI: \(connectedPeripheral.rssi)")
|
||||
|
||||
|
||||
Button(role: .destructive) {
|
||||
if let connectedPeripheral = bleManager.connectedPeripheral,
|
||||
connectedPeripheral.peripheral.state == .connected {
|
||||
bleManager.disconnectPeripheral(reconnect: false)
|
||||
}
|
||||
} label: {
|
||||
Label("Disconnect", systemImage: "antenna.radiowaves.left.and.right.slash")
|
||||
}
|
||||
Button {
|
||||
if !bleManager.sendShutdown(fromUser: node!.user!, toUser: node!.user!, adminIndex: node!.myInfo!.adminIndex) {
|
||||
Logger.mesh.error("Shutdown Failed")
|
||||
|
|
@ -323,6 +357,23 @@ struct Connect: View {
|
|||
} else {
|
||||
isUnsetRegion = false
|
||||
}
|
||||
// Show swipe demo if user hasn't seen it before and we're connected
|
||||
if !hasSeenSwipeDemo && bleManager.isSubscribed && node != nil {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||||
withAnimation(.easeInOut(duration: 0.6)) {
|
||||
swipeDemoOffset = -80
|
||||
showDeleteButton = true
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
|
||||
withAnimation(.easeInOut(duration: 0.6)) {
|
||||
swipeDemoOffset = 0
|
||||
showDeleteButton = false
|
||||
}
|
||||
// Mark as seen so it doesn't appear again
|
||||
hasSeenSwipeDemo = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Logger.data.error("💥 Error fetching node info: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue