-
Notifications
You must be signed in to change notification settings - Fork 83
Fix surface creation and update notification bugs #556
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
Conversation
|
/gemini review |
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.
Code Review
This pull request correctly refactors the logic for surface creation and update notifications. The distinction between new and existing surfaces is now handled more robustly in the SurfaceUpdate case, and DataModelUpdate now correctly triggers a UI refresh for rendered surfaces. The tests have also been updated to reflect these changes. I've added one comment to improve the robustness of the BeginRendering message handler to align it with the new logic for handling new surfaces.
| final String surfaceId = message.surfaceId; | ||
| dataModelForSurface(surfaceId); | ||
| final ValueNotifier<UiDefinition?> notifier = getSurfaceNotifier( | ||
| message.surfaceId, | ||
| surfaceId, | ||
| ); | ||
|
|
||
| // Update the definition with the root component | ||
| final UiDefinition uiDefinition = | ||
| notifier.value ?? UiDefinition(surfaceId: message.surfaceId); | ||
| notifier.value ?? UiDefinition(surfaceId: surfaceId); | ||
| final UiDefinition newUiDefinition = uiDefinition.copyWith( | ||
| rootComponentId: message.root, | ||
| ); | ||
| notifier.value = newUiDefinition; | ||
| genUiLogger.info('Started rendering ${message.surfaceId}'); | ||
| _surfaceUpdates.add(SurfaceUpdated(message.surfaceId, newUiDefinition)); | ||
|
|
||
| genUiLogger.info('Start rendering surface $surfaceId'); | ||
| _surfaceUpdates.add(SurfaceUpdated(surfaceId, newUiDefinition)); |
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 current implementation for BeginRendering assumes that a SurfaceUpdate message has already been received for the given surfaceId. If BeginRendering is the first message for a new surface, it will be created, but a SurfaceUpdated event will be fired instead of SurfaceAdded.
This is inconsistent with the logic in the SurfaceUpdate case, which correctly handles new surfaces by firing SurfaceAdded.
To make this more robust and handle the edge case where BeginRendering creates the surface, consider checking if the surface is new and firing the appropriate event, similar to how it's done in the SurfaceUpdate case.
final String surfaceId = message.surfaceId;
final bool isNewSurface = !_surfaces.containsKey(surfaceId);
dataModelForSurface(surfaceId);
final ValueNotifier<UiDefinition?> notifier = getSurfaceNotifier(
surfaceId,
);
// Update the definition with the root component
final UiDefinition uiDefinition =
notifier.value ?? UiDefinition(surfaceId: surfaceId);
final UiDefinition newUiDefinition = uiDefinition.copyWith(
rootComponentId: message.root,
);
notifier.value = newUiDefinition;
genUiLogger.info('Start rendering surface $surfaceId');
if (isNewSurface) {
_surfaceUpdates.add(SurfaceAdded(surfaceId, newUiDefinition));
} else {
_surfaceUpdates.add(SurfaceUpdated(surfaceId, newUiDefinition));
}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.
Code Review
This pull request correctly refactors the logic for surface creation and update notifications, ensuring SurfaceAdded is fired for new surfaces and SurfaceUpdated for modifications. The changes in GenUiManager and the corresponding test updates in genui_manager_test.dart are well-aligned with this goal.
I've identified a couple of areas for improvement. One is a potential memory leak and unintended side effect in the DataModelUpdate handler. The other is an inconsistency in the BeginRendering handler, which doesn't correctly fire a SurfaceAdded event for new surfaces. Addressing these points will improve the robustness and correctness of the GenUiManager.
| final String surfaceId = message.surfaceId; | ||
| dataModelForSurface(surfaceId); | ||
| final ValueNotifier<UiDefinition?> notifier = getSurfaceNotifier( | ||
| message.surfaceId, | ||
| surfaceId, | ||
| ); | ||
|
|
||
| // Update the definition with the root component | ||
| final UiDefinition uiDefinition = | ||
| notifier.value ?? UiDefinition(surfaceId: message.surfaceId); | ||
| notifier.value ?? UiDefinition(surfaceId: surfaceId); | ||
| final UiDefinition newUiDefinition = uiDefinition.copyWith( | ||
| rootComponentId: message.root, | ||
| ); | ||
| notifier.value = newUiDefinition; | ||
| genUiLogger.info('Started rendering ${message.surfaceId}'); | ||
| _surfaceUpdates.add(SurfaceUpdated(message.surfaceId, newUiDefinition)); | ||
|
|
||
| genUiLogger.info('Start rendering surface $surfaceId'); | ||
| _surfaceUpdates.add(SurfaceUpdated(surfaceId, newUiDefinition)); |
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 current implementation for BeginRendering always fires a SurfaceUpdated event. This is inconsistent with the logic for SurfaceUpdate and can lead to issues on the client side if BeginRendering is the first message for a given surface. In that case, the client would receive a SurfaceUpdated event for a surface it hasn't seen before, instead of the expected SurfaceAdded.
To fix this, you should check if the surface is new before getting the notifier, and then fire SurfaceAdded or SurfaceUpdated accordingly, just like you've done for the SurfaceUpdate case.
final String surfaceId = message.surfaceId;
final bool isNewSurface = !_surfaces.containsKey(surfaceId);
dataModelForSurface(surfaceId);
final ValueNotifier<UiDefinition?> notifier = getSurfaceNotifier(
surfaceId,
);
// Update the definition with the root component
final UiDefinition uiDefinition =
notifier.value ?? UiDefinition(surfaceId: surfaceId);
final UiDefinition newUiDefinition = uiDefinition.copyWith(
rootComponentId: message.root,
);
notifier.value = newUiDefinition;
if (isNewSurface) {
genUiLogger.info('Adding and rendering new surface $surfaceId');
_surfaceUpdates.add(SurfaceAdded(surfaceId, newUiDefinition));
} else {
genUiLogger.info('Start rendering surface $surfaceId');
_surfaceUpdates.add(SurfaceUpdated(surfaceId, newUiDefinition));
}|
/gemini review |
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.
Code Review
This pull request effectively addresses the bugs in surface creation and update notifications by correctly assigning the SurfaceAdded event to the BeginRendering message and ensuring SurfaceUpdated is used for subsequent modifications. The accompanying test updates properly validate this new logic. I've included a couple of suggestions to enhance code conciseness and improve the robustness of one of the tests.
andrewkolos
left a comment
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.
LGTM with nits
Co-authored-by: Andrew Kolos <andrewrkolos@gmail.com>
Co-authored-by: Andrew Kolos <andrewrkolos@gmail.com>
This PR addresses several issues related to surface creation and update notifications in the
genuipackage.Changes:
GenUiManagerto ensure thatSurfaceAddedevents are fired only when a new surface is created, andSurfaceUpdatedevents are fired for all subsequent modifications, including when rendering begins.genui_manager_test.dartto accurately reflect the corrected event firing logic, ensuring that the tests properly validate the behavior ofGenUiManager.