-
Notifications
You must be signed in to change notification settings - Fork 0
fix(ci): restore Android lint compatibility #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
980b862
62d4bd4
d3454b6
e78de74
370bb31
d7cc4e7
35ef91c
3e30877
17425d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -174,7 +174,7 @@ final class DeeplineAppModel: ObservableObject { | |
| try await self.ensureReachableServerBaseURL() | ||
| let envelopes = try await self.client.listMessages(baseURL: self.serverBaseURL, conversationId: conversationId) | ||
| let parsed = self.parseMessages(currentUserId: userId, envelopes: envelopes) | ||
| self.messages[conversationId] = parsed | ||
| self.replaceMessages(parsed, for: conversationId) | ||
| self.updateConversationPreview(conversationId: conversationId, preview: parsed.last?.body) | ||
| } | ||
| } | ||
|
|
@@ -242,7 +242,7 @@ final class DeeplineAppModel: ObservableObject { | |
| } | ||
|
|
||
| let newMessage = parseMessage(currentUserId: currentUserId, envelope: envelope) | ||
| messages[conversationId] = existingMessages + [newMessage] | ||
| replaceMessages(existingMessages + [newMessage], for: conversationId) | ||
| updateConversationPreview(conversationId: conversationId, preview: newMessage.body) | ||
| } | ||
|
|
||
|
|
@@ -353,7 +353,7 @@ final class DeeplineAppModel: ObservableObject { | |
| func loadGroupMembers(conversationId: String) async { | ||
| await performSilentTask { [self] in | ||
| let page = try await self.client.listConversationMembers(baseURL: self.serverBaseURL, conversationId: conversationId) | ||
| self.groupMembers[conversationId] = page.members | ||
| self.replaceGroupMembers(page.members, for: conversationId) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -473,6 +473,16 @@ final class DeeplineAppModel: ObservableObject { | |
| messages[conversationId] ?? [] | ||
| } | ||
|
|
||
| private func replaceMessages(_ newMessages: [DeeplineMessage], for conversationId: String) { | ||
| guard (messages[conversationId] ?? []) != newMessages else { return } | ||
| messages[conversationId] = newMessages | ||
| } | ||
|
|
||
| private func replaceGroupMembers(_ newMembers: [GroupMember], for conversationId: String) { | ||
| guard (groupMembers[conversationId] ?? []) != newMembers else { return } | ||
| groupMembers[conversationId] = newMembers | ||
| } | ||
|
Comment on lines
+476
to
+484
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The 'copy-modify-assign' pattern used here is a known workaround for Xcode 15 compiler issues, but it results in a full dictionary copy on every update, which can impact performance as the number of conversations grows. Using direct subscript assignment within these helpers should still resolve the compiler's type inference issues while maintaining O(1) performance. Additionally, adding a comment explaining the workaround and using consistent parameter naming (e.g., private func replaceMessages(_ newMessages: [DeeplineMessage], for conversationId: String) {
// Workaround for Xcode 15 compiler issues with @Published dictionary updates
guard messages[conversationId] != newMessages else { return }
messages[conversationId] = newMessages
}
private func replaceGroupMembers(_ newMembers: [GroupMember], for conversationId: String) {
// Workaround for Xcode 15 compiler issues with @Published dictionary updates
guard groupMembers[conversationId] != newMembers else { return }
groupMembers[conversationId] = newMembers
} |
||
|
|
||
| func primaryConversationId() -> String? { | ||
| chats.first?.id | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,18 +9,33 @@ final class DeeplineIOSUITests: XCTestCase { | |
| let app = XCUIApplication() | ||
| app.launchArguments.append("-resetDeeplineState") | ||
| app.launchEnvironment["DEEPLINE_SERVER_URL"] = "http://localhost:9091" | ||
| addUIInterruptionMonitor(withDescription: "Notification permission") { alert in | ||
| let alertText = ([alert.label] + alert.staticTexts.allElementsBoundByIndex.map(\.label)).joined(separator: " ") | ||
| guard alertText.localizedCaseInsensitiveContains("notification") else { return false } | ||
| if alert.buttons["Allow"].exists { | ||
| alert.buttons["Allow"].tap() | ||
| } else if alert.buttons.count > 1 { | ||
| alert.buttons.element(boundBy: 1).tap() | ||
| } else if alert.buttons.count > 0 { | ||
| alert.buttons.element(boundBy: 0).tap() | ||
| } else { | ||
| return false | ||
| } | ||
| return true | ||
| } | ||
|
Comment on lines
+12
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| app.launch() | ||
| app.tap() | ||
|
|
||
| let setupButton = app.buttons["Set Up Local Identity"] | ||
| let setupButton = app.buttons["Get Started"] | ||
| XCTAssertTrue(setupButton.waitForExistence(timeout: 10)) | ||
| setupButton.tap() | ||
|
|
||
| let displayNameField = app.textFields["Display name"] | ||
| XCTAssertTrue(displayNameField.waitForExistence(timeout: 10)) | ||
| let displayNameField = app.textFields["Enter your name"] | ||
| XCTAssertTrue(displayNameField.waitForExistence(timeout: 15)) | ||
| displayNameField.tap() | ||
| displayNameField.typeText("Codex Tester") | ||
|
|
||
| let deviceField = app.textFields["Device label"] | ||
| let deviceField = app.textFields["e.g. iPhone 15 Pro"] | ||
| XCTAssertTrue(deviceField.waitForExistence(timeout: 10)) | ||
| deviceField.tap() | ||
| if let currentValue = deviceField.value as? String, !currentValue.isEmpty { | ||
|
|
@@ -31,17 +46,18 @@ final class DeeplineIOSUITests: XCTestCase { | |
|
|
||
| app.buttons["Create Identity"].tap() | ||
|
|
||
| let composer = app.textFields["Write a private note"] | ||
| let composer = app.textFields["Message"] | ||
| if !composer.waitForExistence(timeout: 20) { | ||
| let localNotes = app.staticTexts["Local Notes"] | ||
| XCTAssertTrue(localNotes.waitForExistence(timeout: 20)) | ||
| localNotes.tap() | ||
| } | ||
| XCTAssertTrue(composer.waitForExistence(timeout: 10)) | ||
| XCTAssertTrue(app.buttons["Send"].exists) | ||
| composer.tap() | ||
| composer.typeText("UITest secure note") | ||
| app.buttons["Send"].tap() | ||
| let sendButton = app.buttons["Send"] | ||
| XCTAssertTrue(sendButton.waitForExistence(timeout: 10)) | ||
| sendButton.tap() | ||
| XCTAssertTrue(app.staticTexts["UITest secure note"].waitForExistence(timeout: 10)) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
replaceMessageshelper is a valid workaround for the reported Xcode 15 compiler issues. However, sinceloadMessagesis called frequently via a polling loop (every 3 seconds inChatRoomView), this method will trigger a UI refresh even if the messages haven't changed. Adding an equality check here can prevent unnecessary view updates and potential flickering.