Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
1262377bcb
commit
54d4561158
@ -8,6 +8,7 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
EA837E672F107D6800077F87 /* Bedrock in Frameworks */ = {isa = PBXBuildFile; productRef = EA837E662F107D6800077F87 /* Bedrock */; };
|
||||
EAAE892A2F12DE110075BC8A /* BusinessCardWatch Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = EA837F982F11B16400077F87 /* BusinessCardWatch Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -25,8 +26,29 @@
|
||||
remoteGlobalIDString = EA8379222F105F2600077F87;
|
||||
remoteInfo = BusinessCard;
|
||||
};
|
||||
EAAE892B2F12DE110075BC8A /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = EA83791B2F105F2600077F87 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = EA837F972F11B16400077F87;
|
||||
remoteInfo = "BusinessCardWatch Watch App";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
EAAE892D2F12DE110075BC8A /* Embed Watch Content */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
EAAE892A2F12DE110075BC8A /* BusinessCardWatch Watch App.app in Embed Watch Content */,
|
||||
);
|
||||
name = "Embed Watch Content";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
EA8379232F105F2600077F87 /* BusinessCard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BusinessCard.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
EA8379302F105F2800077F87 /* BusinessCardTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BusinessCardTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@ -110,6 +132,7 @@
|
||||
EA8379332F105F2800077F87 /* BusinessCardTests */,
|
||||
EA83793D2F105F2800077F87 /* BusinessCardUITests */,
|
||||
EA837F992F11B16400077F87 /* BusinessCardWatch Watch App */,
|
||||
EAAE89292F12DE110075BC8A /* Frameworks */,
|
||||
EA8379242F105F2600077F87 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
@ -125,6 +148,13 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAAE89292F12DE110075BC8A /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -135,10 +165,12 @@
|
||||
EA83791F2F105F2600077F87 /* Sources */,
|
||||
EA8379202F105F2600077F87 /* Frameworks */,
|
||||
EA8379212F105F2600077F87 /* Resources */,
|
||||
EAAE892D2F12DE110075BC8A /* Embed Watch Content */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
EAAE892C2F12DE110075BC8A /* PBXTargetDependency */,
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
EA8379252F105F2600077F87 /* BusinessCard */,
|
||||
@ -345,6 +377,11 @@
|
||||
target = EA8379222F105F2600077F87 /* BusinessCard */;
|
||||
targetProxy = EA83793B2F105F2800077F87 /* PBXContainerItemProxy */;
|
||||
};
|
||||
EAAE892C2F12DE110075BC8A /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = EA837F972F11B16400077F87 /* BusinessCardWatch Watch App */;
|
||||
targetProxy = EAAE892B2F12DE110075BC8A /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
|
||||
@ -59,7 +59,9 @@ final class WatchConnectivityService: NSObject {
|
||||
}
|
||||
|
||||
private func sendCardsToWatch(_ cards: [BusinessCard]) {
|
||||
Design.debugLog("WatchConnectivity: Syncing \(cards.count) cards to Watch")
|
||||
guard let session = session else { return }
|
||||
|
||||
Design.debugLog("WatchConnectivity: Syncing \(cards.count) cards to Watch (reachable: \(session.isReachable))")
|
||||
|
||||
let syncableCards = cards.map { card in
|
||||
createSyncableCard(from: card)
|
||||
@ -67,12 +69,26 @@ final class WatchConnectivityService: NSObject {
|
||||
|
||||
do {
|
||||
let encoded = try JSONEncoder().encode(syncableCards)
|
||||
let userInfo: [String: Any] = ["cards": encoded]
|
||||
let message: [String: Any] = ["cards": encoded]
|
||||
|
||||
// Use transferUserInfo instead of updateApplicationContext
|
||||
// This queues the transfer and works even in debug mode
|
||||
session?.transferUserInfo(userInfo)
|
||||
Design.debugLog("WatchConnectivity: Queued \(encoded.count) bytes via transferUserInfo")
|
||||
// ALWAYS update application context - this persists and will be available
|
||||
// when watch app launches, even if not currently reachable
|
||||
do {
|
||||
try session.updateApplicationContext(message)
|
||||
Design.debugLog("WatchConnectivity: Updated application context with \(encoded.count) bytes")
|
||||
} catch {
|
||||
Design.debugLog("WatchConnectivity: updateApplicationContext failed: \(error)")
|
||||
}
|
||||
|
||||
// Also try immediate delivery if reachable
|
||||
if session.isReachable {
|
||||
session.sendMessage(message, replyHandler: nil) { error in
|
||||
Task { @MainActor in
|
||||
Design.debugLog("WatchConnectivity: sendMessage failed: \(error)")
|
||||
}
|
||||
}
|
||||
Design.debugLog("WatchConnectivity: Also sent via sendMessage (reachable)")
|
||||
}
|
||||
} catch {
|
||||
Design.debugLog("WatchConnectivity: ERROR - Failed to encode: \(error)")
|
||||
}
|
||||
@ -81,6 +97,8 @@ final class WatchConnectivityService: NSObject {
|
||||
fileprivate func handleActivation() {
|
||||
isActivated = true
|
||||
|
||||
Design.debugLog("WatchConnectivity: Activation complete - paired: \(session?.isPaired ?? false), installed: \(session?.isWatchAppInstalled ?? false), reachable: \(session?.isReachable ?? false)")
|
||||
|
||||
// Send any pending cards that were queued before activation
|
||||
if let cards = pendingCards {
|
||||
Design.debugLog("WatchConnectivity: Sending \(cards.count) queued cards after activation")
|
||||
@ -89,6 +107,17 @@ final class WatchConnectivityService: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
/// Force a retry - call this after watch app is confirmed running
|
||||
func retrySyncIfNeeded() {
|
||||
guard let session = session else { return }
|
||||
Design.debugLog("WatchConnectivity: Manual retry - paired: \(session.isPaired), installed: \(session.isWatchAppInstalled), reachable: \(session.isReachable)")
|
||||
|
||||
if let cards = pendingCards {
|
||||
pendingCards = nil
|
||||
syncCards(cards)
|
||||
}
|
||||
}
|
||||
|
||||
private func createSyncableCard(from card: BusinessCard) -> SyncableCard {
|
||||
// Get first email, phone, website, location from contact fields
|
||||
let email = card.firstContactField(ofType: "email")?.value ?? ""
|
||||
|
||||
@ -96,6 +96,13 @@ extension WatchConnectivityService: WCSessionDelegate {
|
||||
processReceivedContext(userInfo)
|
||||
}
|
||||
}
|
||||
|
||||
nonisolated func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
|
||||
Task { @MainActor in
|
||||
WatchDesign.debugLog("WatchConnectivity: Received message")
|
||||
processReceivedContext(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Syncable card structure matching iOS side (for decoding)
|
||||
|
||||
@ -16,7 +16,40 @@ final class WatchCardStore {
|
||||
init() {
|
||||
loadDefaultID()
|
||||
WatchDesign.debugLog("WatchCardStore: Initialized, waiting for cards from iPhone")
|
||||
|
||||
// Set up callback for when cards are received from iPhone
|
||||
WatchConnectivityService.shared.onCardsReceived = { [weak self] cards in
|
||||
self?.updateCards(cards)
|
||||
}
|
||||
|
||||
#if targetEnvironment(simulator)
|
||||
// Load sample data on simulator since WatchConnectivity often doesn't work
|
||||
if cards.isEmpty {
|
||||
loadSimulatorSampleData()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if targetEnvironment(simulator)
|
||||
private func loadSimulatorSampleData() {
|
||||
WatchDesign.debugLog("WatchCardStore: Loading simulator sample data")
|
||||
cards = [
|
||||
WatchCard(
|
||||
id: UUID(),
|
||||
displayName: "Test User",
|
||||
role: "iOS Developer",
|
||||
company: "Sample Corp",
|
||||
email: "test@example.com",
|
||||
phone: "+1 555-0123",
|
||||
website: "example.com",
|
||||
location: "San Francisco, CA",
|
||||
isDefault: true,
|
||||
qrCodeImageData: nil
|
||||
)
|
||||
]
|
||||
defaultCardID = cards.first?.id
|
||||
}
|
||||
#endif
|
||||
|
||||
var defaultCard: WatchCard? {
|
||||
guard let defaultCardID else { return cards.first(where: { $0.isDefault }) ?? cards.first }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user