Skip to content
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

InteractiveViewer Control #3645

Merged
merged 3 commits into from
Aug 6, 2024
Merged

InteractiveViewer Control #3645

merged 3 commits into from
Aug 6, 2024

Conversation

ndonkoHenri
Copy link
Contributor

@ndonkoHenri ndonkoHenri commented Jul 15, 2024

Test Code

import flet as ft


def main(page: ft.Page):
    page.add(
        ft.InteractiveViewer(
            expand=True,
            min_scale=0.1,
            max_scale=5,
            boundary_margin=ft.margin.all(20),
            on_interaction_start=lambda e: print(e),
            on_interaction_end=lambda e: print(e),
            on_interaction_update=lambda e: print(e),
            content=ft.Container(
                gradient=ft.LinearGradient(colors=[ft.colors.RED, ft.colors.BLUE]),
            ),
        )
    )


ft.app(target=main)

Capture

interactive-viewer

Summary by Sourcery

This pull request introduces the InteractiveViewerControl to enable panning, zooming, and rotating of content. It also includes enhancements to the createWidget function and the Theme class, along with a bug fix for event string representation.

  • New Features:
    • Introduced InteractiveViewerControl to allow users to pan, zoom, and rotate content within the application.
  • Bug Fixes:
    • Modified event string representation to include data as the last argument, ensuring it is not ignored.
  • Enhancements:
    • Updated createWidget function to support the new InteractiveViewerControl.
    • Extended Theme class to support both ThemeVisualDensity and VisualDensity types.
  • Documentation:
    • Added documentation for the new InteractiveViewer class, detailing its properties and usage.

Copy link
Contributor

sourcery-ai bot commented Jul 15, 2024

Reviewer's Guide by Sourcery

This pull request introduces a new InteractiveViewer control that allows users to pan, zoom, and rotate content. The implementation includes changes to the create_control.dart file to support the new control, modifications to the event.py and theme.py files for event handling and theme adjustments, and the addition of new files interactive_viewer.py and interactive_viewer.dart to define the control and its behavior.

File-Level Changes

Files Changes
sdk/python/packages/flet-core/src/flet_core/interactive_viewer.py
packages/flet/lib/src/controls/interactive_viewer.dart
Added new InteractiveViewer control with event handling for interaction start, update, and end.

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • Continue your discussion with Sourcery by replying directly to review comments.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ndonkoHenri - I've reviewed your changes and found some issues that need to be addressed.

Blocking issues:

  • Potential use of undefined attribute (link)
  • Potential use of undefined attribute (link)
Here's what I looked at during the review
  • 🔴 General issues: 2 blocking issues, 5 other issues
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

@@ -12,6 +12,6 @@ def __str__(self):
attrs = ", ".join(
f"{k}={v!r}"
for k, v in self.__dict__.items()
if k not in ["control", "page", "target"] # ignore these keys
if k not in ["control", "page", "target", "data"] # ignore these keys
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Potential redundancy in ignoring 'data' key

The 'data' key is being ignored in the attribute string construction but then reinserted as the last argument. This seems redundant and could be simplified by not ignoring 'data' in the first place.

Suggested change
if k not in ["control", "page", "target", "data"] # ignore these keys
if k not in ["control", "page", "target"] # ignore these keys

@@ -710,4 +710,6 @@ class Theme:
text_theme: Optional[TextTheme] = field(default=None)
time_picker_theme: Optional[TimePickerTheme] = field(default=None)
tooltip_theme: Optional[TooltipTheme] = field(default=None)
visual_density: ThemeVisualDensity = field(default=ThemeVisualDensity.STANDARD)
visual_density: Union[ThemeVisualDensity, VisualDensity] = field(
default=VisualDensity.STANDARD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Inconsistent default value type

The default value for 'visual_density' is now set to 'VisualDensity.STANDARD', but the type hint includes 'ThemeVisualDensity'. Ensure that 'VisualDensity.STANDARD' is compatible with 'ThemeVisualDensity' to avoid type issues.

def before_update(self):
super().before_update()
assert self.__content.visible, "content must be visible"
self._set_attr_json("alignment", self.__alignment)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Potential use of undefined attribute

The attribute 'self.__alignment' is being used but not defined in the constructor. Ensure that 'self.__alignment' is initialized properly to avoid runtime errors.

super().before_update()
assert self.__content.visible, "content must be visible"
self._set_attr_json("alignment", self.__alignment)
self._set_attr_json("boundaryMargin", self.__boundary_margin)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Potential use of undefined attribute

The attribute 'self.__boundary_margin' is being used but not defined in the constructor. Ensure that 'self.__boundary_margin' is initialized properly to avoid runtime errors.

Widget build(BuildContext context) {
debugPrint("InteractiveViewer build: ${control.id}");

var contentCtrls = children.where((c) => c.isVisible);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Potential performance issue with filtering children

Filtering the children list to find visible controls could be optimized by using a more efficient data structure or caching the result if this operation is performed frequently.

Suggested change
var contentCtrls = children.where((c) => c.isVisible);
var contentCtrls = <Control>[];
for (var child in children) {
if (child.isVisible) {
contentCtrls.add(child);
}
}

debugPrint("InteractiveViewer build: ${control.id}");

var contentCtrls = children.where((c) => c.isVisible);
bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Potential nullability issue with adaptive

The variable 'adaptive' is declared as 'bool?' but is later used in a context where a non-nullable 'bool' might be expected. Consider ensuring 'adaptive' is non-null before usage.

Comment on lines +38 to +47
var interactiveViewer = InteractiveViewer(
panEnabled: control.attrBool("panEnabled", true)!,
scaleEnabled: control.attrBool("scaleEnabled", true)!,
trackpadScrollCausesScale:
control.attrBool("trackpadScrollCausesScale", false)!,
constrained: control.attrBool("constrained", true)!,
maxScale: control.attrDouble("maxScale", 2.5)!,
minScale: control.attrDouble("minScale", 0.8)!,
interactionEndFrictionCoefficient:
control.attrDouble("interactionEndFrictionCoefficient", 0.0000135)!,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Long constructor call

The constructor call for 'InteractiveViewer' is quite long and could benefit from breaking it down into smaller, more manageable pieces or using a builder pattern for better readability.

@ndonkoHenri ndonkoHenri added controls feature request Suggestion/Request for additional feature labels Jul 15, 2024
@FeodorFitsner
Copy link
Contributor

Could you please resolve conflict here?

# Conflicts:
#	sdk/python/packages/flet-core/src/flet_core/theme.py
@FeodorFitsner FeodorFitsner merged commit 7d9fb31 into main Aug 6, 2024
2 checks passed
@ndonkoHenri ndonkoHenri deleted the interactive-viewer-control branch August 17, 2024 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
controls feature request Suggestion/Request for additional feature
Projects
Status: ✅ Done
Development

Successfully merging this pull request may close these issues.

2 participants