Skip to content

Commit 690077f

Browse files
authored
Merge pull request #18 from BlockedPath/codex/sync-main
[codex] Fix iOS warning cleanup
2 parents 414a3b7 + 7173814 commit 690077f

7 files changed

Lines changed: 54 additions & 50 deletions

File tree

ios/CodexMeterApp/CodexMeterApp.xcodeproj/project.pbxproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
74ACD947130193A7D90283ED /* UsageWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = E664385FA963DE22DD0B46BC /* UsageWidget.swift */; };
1616
A5237C0A03A2D901589A44EB /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE995ECA438F57D71DA72F0F /* ContentView.swift */; };
1717
A7C10B8087861DE75EECF39D /* MDNSBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0BC3573F66A4836E448C92 /* MDNSBrowser.swift */; };
18-
FDAA4EA4A4735763485D9D69 /* CodexMeterAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDDAD089F71A1A8EDAD51DA0 /* CodexMeterAppTests.swift */; };
1918
/* End PBXBuildFile section */
2019

2120
/* Begin PBXContainerItemProxy section */
@@ -59,7 +58,6 @@
5958
79F45A0EE1F102187D9268AB /* MeterDiscoveryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeterDiscoveryTests.swift; sourceTree = "<group>"; };
6059
7EE906304FAD5C66673F7722 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
6160
B40854E30881C891D1F40B3A /* CodexMeterAppWidget.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CodexMeterAppWidget.entitlements; sourceTree = "<group>"; };
62-
BDDAD089F71A1A8EDAD51DA0 /* CodexMeterAppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodexMeterAppTests.swift; sourceTree = "<group>"; };
6361
C8180B6886C50FA4DEA8992D /* BLEManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLEManager.swift; sourceTree = "<group>"; };
6462
E664385FA963DE22DD0B46BC /* UsageWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsageWidget.swift; sourceTree = "<group>"; };
6563
EC0040FEB18C46FF8FA88AF2 /* MeterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeterViewModel.swift; sourceTree = "<group>"; };
@@ -92,7 +90,6 @@
9290
3499A71A1358CD14DC689F25 /* CodexMeterAppTests */ = {
9391
isa = PBXGroup;
9492
children = (
95-
BDDAD089F71A1A8EDAD51DA0 /* CodexMeterAppTests.swift */,
9693
79F45A0EE1F102187D9268AB /* MeterDiscoveryTests.swift */,
9794
);
9895
path = CodexMeterAppTests;
@@ -255,7 +252,6 @@
255252
isa = PBXSourcesBuildPhase;
256253
buildActionMask = 2147483647;
257254
files = (
258-
FDAA4EA4A4735763485D9D69 /* CodexMeterAppTests.swift in Sources */,
259255
055301C29AB48432A9267FF6 /* MeterDiscoveryTests.swift in Sources */,
260256
);
261257
runOnlyForDeploymentPostprocessing = 0;

ios/CodexMeterApp/CodexMeterApp/Info.plist

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@
4545
<string>bluetooth-central</string>
4646
<string>fetch</string>
4747
</array>
48+
<key>UIRequiresFullScreen</key>
49+
<true/>
50+
<key>UISupportedInterfaceOrientations</key>
51+
<array>
52+
<string>UIInterfaceOrientationPortrait</string>
53+
</array>
4854
<key>UILaunchScreen</key>
4955
<dict/>
5056
</dict>

ios/CodexMeterApp/CodexMeterApp/Services/BLEManager.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ final class BLEManager: NSObject, ObservableObject {
109109

110110
// MARK: - CBCentralManagerDelegate
111111

112-
extension BLEManager: CBCentralManagerDelegate {
112+
extension BLEManager: @preconcurrency CBCentralManagerDelegate {
113113
func centralManagerDidUpdateState(_ central: CBCentralManager) {
114114
switch central.state {
115115
case .poweredOn:
@@ -176,7 +176,7 @@ extension BLEManager: CBCentralManagerDelegate {
176176

177177
// MARK: - CBPeripheralDelegate
178178

179-
extension BLEManager: CBPeripheralDelegate {
179+
extension BLEManager: @preconcurrency CBPeripheralDelegate {
180180
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
181181
guard let services = peripheral.services else { return }
182182
for service in services {

ios/CodexMeterApp/CodexMeterApp/Services/MDNSBrowser.swift

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Foundation
33
import Darwin
44

55
/// MDNSBrowser discovers HTTP services on the local network and publishes resolved URLs.
6+
@MainActor
67
final class MDNSServiceBrowser: NSObject {
78
static let shared = MDNSServiceBrowser()
89

@@ -26,22 +27,18 @@ final class MDNSServiceBrowser: NSObject {
2627
}
2728

2829
func startBrowsing() {
29-
DispatchQueue.main.async {
30-
guard !self.isBrowsing else { return }
31-
self.isBrowsing = true
32-
self.discoveredURLs.removeAll()
33-
self.netServiceBrowser.searchForServices(ofType: self.serviceType, inDomain: self.domain)
34-
}
30+
guard !isBrowsing else { return }
31+
isBrowsing = true
32+
discoveredURLs.removeAll()
33+
netServiceBrowser.searchForServices(ofType: serviceType, inDomain: domain)
3534
}
3635

3736
func stopBrowsing() {
38-
DispatchQueue.main.async {
39-
guard self.isBrowsing else { return }
40-
self.isBrowsing = false
41-
self.netServiceBrowser.stop()
42-
self.servicesResolving.removeAll()
43-
self.discoveredURLs.removeAll()
44-
}
37+
guard isBrowsing else { return }
38+
isBrowsing = false
39+
netServiceBrowser.stop()
40+
servicesResolving.removeAll()
41+
discoveredURLs.removeAll()
4542
}
4643

4744
private func cleanup(service: NetService) {
@@ -130,51 +127,45 @@ extension MDNSServiceBrowser {
130127
}
131128
}
132129

133-
extension MDNSServiceBrowser: NetServiceBrowserDelegate {
130+
extension MDNSServiceBrowser: @preconcurrency NetServiceBrowserDelegate {
134131
func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
135-
DispatchQueue.main.async {
136-
if !self.servicesResolving.contains(service) {
137-
self.servicesResolving.insert(service)
138-
service.delegate = self
139-
service.resolve(withTimeout: 5.0)
140-
}
132+
if !servicesResolving.contains(service) {
133+
servicesResolving.insert(service)
134+
service.delegate = self
135+
service.resolve(withTimeout: 5.0)
141136
}
142137
}
143138

144139
func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) {
145-
DispatchQueue.main.async {
146-
self.servicesResolving.remove(service)
147-
if let urlString = self.urlString(from: service) {
148-
self.discoveredURLs.remove(urlString)
149-
}
140+
servicesResolving.remove(service)
141+
if let urlString = urlString(from: service) {
142+
discoveredURLs.remove(urlString)
150143
}
151144
}
152145

153146
func netServiceBrowserDidStopSearch(_ browser: NetServiceBrowser) {
154-
DispatchQueue.main.async { self.isBrowsing = false }
147+
isBrowsing = false
155148
}
156149

157150
func netServiceBrowser(_ browser: NetServiceBrowser, didNotSearch errorDict: [String : NSNumber]) {
158-
DispatchQueue.main.async { self.isBrowsing = false }
151+
isBrowsing = false
159152
}
160153
}
161154

162-
extension MDNSServiceBrowser: NetServiceDelegate {
155+
extension MDNSServiceBrowser: @preconcurrency NetServiceDelegate {
163156
func netServiceDidResolveAddress(_ sender: NetService) {
164-
DispatchQueue.main.async {
165-
guard self.servicesResolving.contains(sender) else { self.cleanup(service: sender); return }
166-
guard self.isCodexMeterService(sender) else { self.cleanup(service: sender); return }
167-
guard let urlString = self.urlString(from: sender) else { self.cleanup(service: sender); return }
168-
if !self.discoveredURLs.contains(urlString) {
169-
self.discoveredURLs.insert(urlString)
170-
self.discoveryPublisher.send((urlString, sender.name))
171-
}
172-
self.cleanup(service: sender)
157+
guard servicesResolving.contains(sender) else { cleanup(service: sender); return }
158+
guard isCodexMeterService(sender) else { cleanup(service: sender); return }
159+
guard let urlString = urlString(from: sender) else { cleanup(service: sender); return }
160+
if !discoveredURLs.contains(urlString) {
161+
discoveredURLs.insert(urlString)
162+
discoveryPublisher.send((urlString, sender.name))
173163
}
164+
cleanup(service: sender)
174165
}
175166

176167
func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
177-
DispatchQueue.main.async { self.cleanup(service: sender) }
168+
cleanup(service: sender)
178169
}
179170

180171
func netService(_ sender: NetService, didUpdateTXTRecord data: Data) {

ios/CodexMeterApp/CodexMeterApp/ViewModels/MeterViewModel.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ final class MeterViewModel: ObservableObject {
103103
for await pair in MDNSServiceBrowser.shared.discoveriesAsync() {
104104
let (url, name) = pair
105105
// process discovery on MainActor (self is @MainActor)
106-
await self.processDiscovery(url: url, name: name)
106+
self.processDiscovery(url: url, name: name)
107107
}
108108
}
109109
}
@@ -119,7 +119,7 @@ final class MeterViewModel: ObservableObject {
119119
if wasEmpty {
120120
self.serverURL = url
121121
// Auto-start: this was an mDNS discovery, kick off fetch + timers
122-
beginPolling()
122+
beginUsagePolling()
123123
}
124124
}
125125

@@ -130,12 +130,13 @@ final class MeterViewModel: ObservableObject {
130130
if serverURL.isEmpty {
131131
MDNSServiceBrowser.shared.startBrowsing()
132132
}
133+
beginDisplayScanning()
133134
guard !serverURL.isEmpty else { return }
134-
beginPolling()
135+
beginUsagePolling()
135136
}
136137

137-
/// Start fetch + BLE timers. Called from start() or after mDNS discovery.
138-
private func beginPolling() {
138+
/// Start usage fetch + refresh timer. Called from start() or after mDNS discovery.
139+
private func beginUsagePolling() {
139140
// Avoid double-starting
140141
guard fetchTimer == nil else { return }
141142

@@ -144,6 +145,11 @@ final class MeterViewModel: ObservableObject {
144145
fetchTimer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { [weak self] _ in
145146
Task { @MainActor [weak self] in await self?.fetchUsage() }
146147
}
148+
}
149+
150+
/// BLE display scanning should not depend on HTTP daemon discovery.
151+
private func beginDisplayScanning() {
152+
guard bleTimer == nil else { return }
147153

148154
ble.startScanning()
149155
bleTimer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] _ in

ios/CodexMeterApp/CodexMeterAppTests/MeterDiscoveryTests.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ final class MeterDiscoveryTests: XCTestCase {
1515
let name = "codexmeter"
1616
var received = false
1717
for _ in 0..<10 where !received {
18-
MDNSServiceBrowser.shared.discoveryPublisher.send((url, name))
18+
await MainActor.run {
19+
MDNSServiceBrowser.shared.discoveryPublisher.send((url, name))
20+
}
1921
try await Task.sleep(nanoseconds: 100_000_000) // 100ms
2022
received = await MainActor.run {
2123
vm.discoveredServices.contains { $0.url == url && $0.name == name }

ios/CodexMeterApp/project.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ targets:
4848
- fetch
4949
UIApplicationSceneManifest:
5050
UIApplicationSupportsMultipleScenes: false
51+
UIRequiresFullScreen: true
52+
UISupportedInterfaceOrientations:
53+
- UIInterfaceOrientationPortrait
5154
UILaunchScreen: {}
5255
NSAppTransportSecurity:
5356
NSAllowsArbitraryLoads: true

0 commit comments

Comments
 (0)