Skip to content
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
24 changes: 23 additions & 1 deletion Magic Switch/AppDelegate/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,15 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
private var pingObserver: NSObjectProtocol?
/// Resets the status-bar icon back to its real state after a Ping flash.
private var pingFlashTimer: DispatchSourceTimer?
/// Observers for inbound peripheral-handoff posts from `IncomingConnection`.
/// Observers for inbound full-set peripheral-handoff posts from
/// `IncomingConnection`.
private var transferReceiveObserver: NSObjectProtocol?
private var transferReleaseObserver: NSObjectProtocol?
/// Same, for single-peripheral switches — posted both by the local
/// per-peripheral senders and by the incoming `.connectOne` /
/// `.unregisterOne` handlers.
private var transferIncomingOneObserver: NSObjectProtocol?
private var transferOutgoingOneObserver: NSObjectProtocol?
/// Direction the status-bar icon should currently advertise. `idle` falls
/// through to the normal/needs-attention logic in `refreshStatusBarIcon`.
private enum TransferState {
Expand Down Expand Up @@ -138,6 +144,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
if let token = transferReleaseObserver {
NotificationCenter.default.removeObserver(token)
}
if let token = transferIncomingOneObserver {
NotificationCenter.default.removeObserver(token)
}
if let token = transferOutgoingOneObserver {
NotificationCenter.default.removeObserver(token)
}
}

// MARK: - Setup Methods
Expand Down Expand Up @@ -300,6 +312,16 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
) { [weak self] _ in
self?.beginTransferAutoEnd(.sending)
}
transferIncomingOneObserver = NotificationCenter.default.addObserver(
forName: .magicSwitchPeripheralIncoming, object: nil, queue: .main
) { [weak self] _ in
self?.beginTransferAutoEnd(.receiving)
}
transferOutgoingOneObserver = NotificationCenter.default.addObserver(
forName: .magicSwitchPeripheralOutgoing, object: nil, queue: .main
) { [weak self] _ in
self?.beginTransferAutoEnd(.sending)
}
}

private func statusBarTooltip() -> String {
Expand Down
14 changes: 14 additions & 0 deletions Magic Switch/Manager/IncomingConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ extension Notification.Name {
/// status-bar icon to the "sending peripherals" state.
static let magicSwitchReceivedUnregisterAll = Notification.Name(
"magicSwitchReceivedUnregisterAll")
/// Per-peripheral counterparts of the `…ConnectAll` / `…UnregisterAll`
/// signals above: the same status-bar arrows, but for a single-device
/// switch. Posted both by this Mac's per-peripheral senders
/// (`takePeripheralFromPeer` / `sendPeripheralToPeer`) and by the incoming
/// `.connectOne` / `.unregisterOne` handlers, so both Macs show arrows
/// pointing the same physical way during a one-peripheral handoff.
static let magicSwitchPeripheralIncoming = Notification.Name(
"magicSwitchPeripheralIncoming")
static let magicSwitchPeripheralOutgoing = Notification.Name(
"magicSwitchPeripheralOutgoing")
}

/// Per-accept handler. Owns the NWConnection, its SecureChannel, idle/total
Expand Down Expand Up @@ -264,6 +274,8 @@ final class IncomingConnection {
let store = bluetoothStore
let address = message
DispatchQueue.main.async {
// Peripheral is leaving this Mac for the peer — flash the sending arrow.
NotificationCenter.default.post(name: .magicSwitchPeripheralOutgoing, object: nil)
if let peripheral = store.peripherals.first(where: { $0.id == address }) {
store.unregisterFromPC(peripheral)
}
Expand All @@ -281,6 +293,8 @@ final class IncomingConnection {
let store = bluetoothStore
let address = message
DispatchQueue.main.async {
// Peripheral is arriving at this Mac — flash the receiving arrow.
NotificationCenter.default.post(name: .magicSwitchPeripheralIncoming, object: nil)
if let peripheral = store.peripherals.first(where: { $0.id == address }) {
store.connectPeripheral(peripheral)
}
Expand Down
5 changes: 5 additions & 0 deletions Magic Switch/Model/Store/BluetoothPeripheralStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,9 @@ final class BluetoothPeripheralStore: NSObject, ObservableObject, BluetoothPerip
return
}

// Peripheral is arriving at this Mac — flash the receiving arrow, the same
// signal the full-set take raises on the menu-bar icon.
NotificationCenter.default.post(name: .magicSwitchPeripheralIncoming, object: nil)
setConnectionState(.connecting, for: peripheral.id)
schedulePairWatchdog(for: peripheral, announceTimeout: true)
networkStore.executeUnregisterOne(address: peripheral.id, on: device) {
Expand Down Expand Up @@ -501,6 +504,8 @@ final class BluetoothPeripheralStore: NSObject, ObservableObject, BluetoothPerip
unregisterFromPC(peripheral)
return
}
// Peripheral is leaving this Mac for the peer — flash the sending arrow.
NotificationCenter.default.post(name: .magicSwitchPeripheralOutgoing, object: nil)
unregisterFromPC(peripheral)
waitForLocalDisconnect(of: peripheral) { success in
guard success else {
Expand Down