Skip to content

Generators#

Python Control#

flet_pkg.core.generators.python_control #

Generator for the main Python control file.

Produces the primary control class (e.g., onesignal.py) following the Flet 0.80.x+ extension pattern with @ft.control(), sub-module properties, event handlers, and async methods.

PythonControlGenerator #

Bases: CodeGenerator

Generates the main Python control file.

generate #

generate(plan: GenerationPlan) -> dict[str, str]

Generate the main Python control file.

Parameters:

Name Type Description Default
plan GenerationPlan

Generation plan produced by the analyzer.

required

Returns:

Type Description
dict[str, str]

Mapping of filename to generated source code.

Source code in src/flet_pkg/core/generators/python_control.py
def generate(self, plan: GenerationPlan) -> dict[str, str]:
    """Generate the main Python control file.

    Args:
        plan: Generation plan produced by the analyzer.

    Returns:
        Mapping of filename to generated source code.
    """
    control_snake = plan.control_name_snake or camel_to_snake(plan.control_name)
    filename = f"{control_snake}.py"
    lines: list[str] = []

    # Module docstring
    kind = "Service" if plan.base_class == "ft.Service" else "Control"
    lines.append('"""')
    lines.append(f"{plan.control_name} {kind} for {plan.package_name}.")
    if plan.description:
        lines.append(f"\n{plan.description}")
    lines.append('"""')

    # Imports
    is_service = plan.base_class == "ft.Service"
    lines.append("")
    all_props = list(plan.properties)
    for sc in self._flatten_sub_controls(plan.sub_controls):
        all_props.extend(sc.properties)
    needs_field = bool(plan.sub_modules) or any(
        p.default_value.startswith("field(") for p in all_props
    )
    if needs_field:
        lines.append("from dataclasses import field")

    # Only import Any when needed (service _invoke_method, method signatures,
    # properties, or sub-control properties)
    needs_any = (
        is_service
        or any("Any" in p.python_type for m in plan.main_methods for p in m.params)
        or any("Any" in m.return_type for m in plan.main_methods)
        or any("Any" in p.python_type for p in plan.properties)
        or any("Any" in p.python_type for sc in plan.sub_controls for p in sc.properties)
    )
    if needs_any:
        lines.append("from typing import Any, Optional")
    else:
        lines.append("from typing import Optional")
    lines.append("")
    lines.append("import flet as ft")
    lines.append("")

    # Sub-module imports
    for sub in plan.sub_modules:
        lines.append(f"from {plan.package_name}.{sub.module_name} import {sub.class_name}")

    # Type imports — only import types actually used by properties/events
    type_imports: list[str] = []
    for event in plan.events:
        type_imports.append(event.event_class_name)
    # Sub-control event types
    for sub in self._flatten_sub_controls(plan.sub_controls):
        for event in sub.events:
            type_imports.append(event.event_class_name)
    # Add error event
    type_imports.append(plan.error_event_class or f"{plan.control_name}ErrorEvent")

    # Collect type names referenced by properties AND method signatures
    used_type_names: set[str] = set()

    # Gather all type strings to scan: properties + method params + returns
    type_strings: list[str] = [p.python_type for p in plan.properties]
    for method in plan.main_methods:
        type_strings.append(method.return_type)
        for p in method.params:
            type_strings.append(p.python_type)
    for sub in plan.sub_modules:
        for method in sub.methods:
            type_strings.append(method.return_type)
            for p in method.params:
                type_strings.append(p.python_type)

    for type_str in type_strings:
        for enum in plan.enums:
            if enum.python_name in type_str:
                used_type_names.add(enum.python_name)
        for stub in plan.stub_data_classes:
            if stub.python_name in type_str:
                used_type_names.add(stub.python_name)

    for enum in plan.enums:
        if enum.python_name in used_type_names:
            type_imports.append(enum.python_name)
    for stub in plan.stub_data_classes:
        if stub.python_name in used_type_names:
            type_imports.append(stub.python_name)
    if type_imports:
        lines.append(f"from {plan.package_name}.types import (")
        for imp in sorted(set(type_imports)):
            lines.append(f"    {imp},")
        lines.append(")")

    lines.append("")
    lines.append("")

    # Sub-control classes (emitted before the main class for forward refs)
    for sub in self._flatten_sub_controls(plan.sub_controls):
        lines.extend(self._render_sub_control(sub))
        lines.append("")
        lines.append("")

    # Class definition
    lines.append(f'@ft.control("{plan.control_name}")')
    lines.append(f"class {plan.control_name}({plan.base_class}):")
    lines.append('    """')
    lines.append(f"    {plan.control_name} integration for Flet applications.")
    lines.append("")
    lines.append("    Example:")
    lines.append("        ```python")
    lines.append("        import flet as ft")
    lines.append(f"        import {plan.package_name} as pkg")
    lines.append("")
    lines.append("        async def main(page: ft.Page):")

    if plan.base_class == "ft.Service":
        if plan.properties:
            prop_examples = []
            for prop in plan.properties[:2]:
                if prop.python_type in ("str", "str | None"):
                    prop_examples.append(f'{prop.python_name}="..."')
                elif prop.python_type == "bool":
                    prop_examples.append(f"{prop.python_name}=True")
            props_str = ", ".join(prop_examples) if prop_examples else ""
            lines.append(f"            svc = pkg.{plan.control_name}({props_str})")
        else:
            lines.append(f"            svc = pkg.{plan.control_name}()")
        lines.append("            page.services.append(svc)")
    else:
        lines.append(f"            widget = pkg.{plan.control_name}()")
        lines.append("            page.add(widget)")

    lines.append("")
    lines.append("        ft.run(main)")
    lines.append("        ```")
    lines.append('    """')
    lines.append("")

    # Properties (dataclass fields sent to Flutter)
    for prop in plan.properties:
        default = prop.default_value
        lines.append(f"    {prop.python_name}: {prop.python_type} = {default}")
        if prop.docstring:
            lines.append(f'    """{prop.docstring}"""')
        lines.append("")

    # Event handlers
    for event in plan.events:
        attr = event.python_attr_name
        evt_cls = event.event_class_name
        lines.append(f"    {attr}: Optional[ft.EventHandler[{evt_cls}]] = None")
        desc = event.dart_event_name.replace("_", " ")
        lines.append(f'    """Called when {desc} occurs."""')
        lines.append("")

    # Error event handler
    error_cls = plan.error_event_class or f"{plan.control_name}ErrorEvent"
    lines.append(f"    on_error: Optional[ft.EventHandler[{error_cls}]] = None")
    lines.append('    """Called when an error occurs in the SDK."""')
    lines.append("")

    # Sub-module private fields
    for sub in plan.sub_modules:
        lines.append(
            f"    _{sub.module_name}: {sub.class_name} = field("
            f'default=None, init=False, metadata={{"skip": True}})'
        )
    if plan.sub_modules:
        lines.append("")

    # init() method
    if plan.sub_modules:
        lines.append("    def init(self):")
        lines.append('        """Initialize the service and sub-modules."""')
        lines.append("        super().init()")
        for sub in plan.sub_modules:
            lines.append(f"        self._{sub.module_name} = {sub.class_name}(self)")
        lines.append("")

    # Sub-module properties
    for sub in plan.sub_modules:
        lines.append("    @property")
        lines.append(f"    def {sub.module_name}(self) -> {sub.class_name}:")
        mod_title = sub.module_name.replace("_", " ").title()
        lines.append(f'        """Access the {mod_title} namespace."""')
        lines.append(f"        if self._{sub.module_name} is None:")
        lines.append(f"            self._{sub.module_name} = {sub.class_name}(self)")
        lines.append(f"        return self._{sub.module_name}")
        lines.append("")

    # Main methods
    for method in plan.main_methods:
        lines.extend(self._render_method(method, plan))
        lines.append("")

    # Platform guard and invoke_method only for service extensions
    # (UI controls are pure Dart widgets that work on all platforms)
    is_service = plan.base_class == "ft.Service"
    if is_service:
        lines.append("    def _is_supported_platform(self) -> bool:")
        lines.append(
            f'        """Check if the current platform supports {plan.control_name}."""'
        )
        lines.append("        if not self.page:")
        lines.append("            return False")
        lines.append("        return self.page.platform in (")
        lines.append("            ft.PagePlatform.ANDROID,")
        lines.append("            ft.PagePlatform.IOS,")
        lines.append("            ft.PagePlatform.MACOS,")
        lines.append("            ft.PagePlatform.WINDOWS,")
        lines.append("            ft.PagePlatform.LINUX,")
        lines.append("        )")
        lines.append("")

        lines.append("    async def _invoke_method(")
        lines.append("        self,")
        lines.append("        method_name: str,")
        lines.append("        arguments: Optional[dict[str, Any]] = None,")
        lines.append("        timeout: Optional[float] = None,")
        lines.append("    ) -> Any:")
        lines.append('        """Internal method for invoking Flutter methods."""')
        lines.append("        if not self._is_supported_platform():")
        lines.append(
            "            platform_name = self.page.platform.value if self.page else 'unknown'"
        )
        lines.append("            raise ft.FletUnsupportedPlatformException(")
        lines.append(
            f'                f"{plan.control_name} is only supported on Android and iOS. "'
        )
        lines.append('                f"Current platform: {platform_name}. "')
        lines.append("                f\"Method '{method_name}' cannot be executed.\"")
        lines.append("            )")
        lines.append("        effective_timeout = timeout if timeout is not None else 25.0")
        lines.append("        return await super()._invoke_method(")
        lines.append("            method_name=method_name,")
        lines.append("            arguments=arguments or {},")
        lines.append("            timeout=effective_timeout,")
        lines.append("        )")
        lines.append("")

    files = {filename: "\n".join(lines)}

    # Generate sibling widget Python files
    for sibling in plan.sibling_widgets:
        sib_snake = sibling.control_name_snake or camel_to_snake(sibling.control_name)
        sib_file = f"{sib_snake}.py"
        files[sib_file] = self._generate_sibling(sibling, plan)

    return files

Python Sub-Modules#

flet_pkg.core.generators.python_submodule #

Generator for Python sub-module files.

Produces one file per sub-module (e.g., user.py, notifications.py) following the composition pattern used in flet-onesignal.

PythonSubModuleGenerator #

Bases: CodeGenerator

Generates Python sub-module files.

generate #

generate(plan: GenerationPlan) -> dict[str, str]

Generate one Python file per sub-module.

Parameters:

Name Type Description Default
plan GenerationPlan

Generation plan produced by the analyzer.

required

Returns:

Type Description
dict[str, str]

Mapping of filename to generated source code.

Source code in src/flet_pkg/core/generators/python_submodule.py
def generate(self, plan: GenerationPlan) -> dict[str, str]:
    """Generate one Python file per sub-module.

    Args:
        plan: Generation plan produced by the analyzer.

    Returns:
        Mapping of filename to generated source code.
    """
    files: dict[str, str] = {}
    for sub in plan.sub_modules:
        filename = f"{sub.module_name}.py"
        content = self._render_submodule(sub, plan)
        files[filename] = content
    return files

Python Types#

flet_pkg.core.generators.python_types #

Generator for the Python types file.

Produces types.py with enum classes and event dataclasses that mirror the Dart SDK's types.

PythonTypesGenerator #

Bases: CodeGenerator

Generates types.py with enums and event dataclasses.

generate #

generate(plan: GenerationPlan) -> dict[str, str]

Generate types.py with enums, event dataclasses, and sub-control classes.

Parameters:

Name Type Description Default
plan GenerationPlan

Generation plan produced by the analyzer.

required

Returns:

Type Description
dict[str, str]

Mapping of filename to generated source code.

Source code in src/flet_pkg/core/generators/python_types.py
def generate(self, plan: GenerationPlan) -> dict[str, str]:
    """Generate ``types.py`` with enums, event dataclasses, and sub-control classes.

    Args:
        plan: Generation plan produced by the analyzer.

    Returns:
        Mapping of filename to generated source code.
    """
    # Always generate types.py — the error event class is always
    # imported by the main control file.

    lines: list[str] = []

    # Module docstring
    lines.append('"""')
    lines.append(f"Types, enums, and dataclasses for {plan.package_name}.")
    lines.append('"""')
    lines.append("")
    lines.append("from __future__ import annotations")
    lines.append("")

    # Imports
    lines.append("from dataclasses import dataclass")
    if plan.enums:
        lines.append("from enum import Enum")
    lines.append("from typing import Optional")
    lines.append("")
    lines.append("import flet as ft")
    lines.append("")
    lines.append("")

    # Enums
    for enum in plan.enums:
        lines.append(f"class {enum.python_name}(Enum):")
        if enum.docstring:
            lines.extend(self._format_docstring(enum.docstring, "    "))
        else:
            lines.append(f'    """{enum.python_name} enum."""')
        lines.append("")
        for val_name, val_value, val_doc in enum.values:
            # Convert camelCase to UPPER_SNAKE_CASE (e.g. sdkUnavailable → SDK_UNAVAILABLE)
            py_name = camel_to_snake(val_name).upper()
            lines.append(f'    {py_name} = "{val_value}"')
            if val_doc:
                lines.append(f'    """{val_doc}"""')
            else:
                lines.append(f'    """{val_name}."""')
            lines.append("")
        lines.append("")

    # Event dataclasses (deduplicate by class name — multiple events
    # can share the same Stream<T> type, e.g. onMessage and onMessageOpenedApp
    # both use Stream<RemoteMessage>)
    seen_event_classes: set[str] = set()
    for event in plan.events:
        if event.event_class_name in seen_event_classes:
            continue
        seen_event_classes.add(event.event_class_name)
        lines.append("")
        lines.append("@dataclass")
        lines.append(f'class {event.event_class_name}(ft.Event["{plan.control_name}"]):')
        event_desc = event.dart_event_name.replace("_", " ")
        lines.append(f'    """Event fired when {event_desc} occurs."""')
        lines.append("")

        for field_name, field_type in event.fields:
            if field_type == "dict":
                lines.append(f"    {field_name}: dict | None = None")
            elif field_type == "bool":
                lines.append(f"    {field_name}: bool = False")
            else:
                opt = self._optional_type(field_type)
                lines.append(f"    {field_name}: {opt} = None")
            field_desc = field_name.replace("_", " ").capitalize()
            lines.append(f'    """{field_desc}."""')
            lines.append("")

    # Sibling widget event dataclasses
    for sibling in plan.sibling_widgets:
        for event in sibling.events:
            if event.event_class_name in seen_event_classes:
                continue
            seen_event_classes.add(event.event_class_name)
            lines.append("")
            lines.append("@dataclass")
            lines.append(f'class {event.event_class_name}(ft.Event["{sibling.control_name}"]):')
            event_desc = event.dart_event_name.replace("_", " ")
            lines.append(f'    """Event fired when {event_desc} occurs."""')
            lines.append("")

            for field_name, field_type in event.fields:
                if field_type == "dict":
                    lines.append(f"    {field_name}: dict = None")
                elif field_type == "bool":
                    lines.append(f"    {field_name}: bool = False")
                else:
                    opt = self._optional_type(field_type)
                    lines.append(f"    {field_name}: {opt} = None")
                field_desc = field_name.replace("_", " ").capitalize()
                lines.append(f'    """{field_desc}."""')
                lines.append("")

    # Sub-control event dataclasses
    for sub in self._flatten_sub_controls(plan.sub_controls):
        for event in sub.events:
            if event.event_class_name in seen_event_classes:
                continue
            seen_event_classes.add(event.event_class_name)
            lines.append("")
            lines.append("@dataclass")
            lines.append(f'class {event.event_class_name}(ft.Event["{sub.control_name}"]):')
            event_desc = event.dart_event_name.replace("_", " ")
            lines.append(f'    """Event fired when {event_desc} occurs."""')
            lines.append("")

            for field_name, field_type in event.fields:
                if field_type == "dict":
                    lines.append(f"    {field_name}: dict | None = None")
                elif field_type == "bool":
                    lines.append(f"    {field_name}: bool = False")
                else:
                    opt = self._optional_type(field_type)
                    lines.append(f"    {field_name}: {opt} = None")
                field_desc = field_name.replace("_", " ").capitalize()
                lines.append(f'    """{field_desc}."""')
                lines.append("")

    # Stub data classes (re-exported types from platform_interface)
    for stub in plan.stub_data_classes:
        lines.append("")
        lines.append("@dataclass")
        lines.append(f"class {stub.python_name}:")
        if stub.docstring:
            lines.append(f'    """{stub.docstring}"""')
        else:
            lines.append(f'    """{stub.python_name} data class."""')
        lines.append("")
        for field_name, field_type in stub.fields:
            if field_type == "dict":
                lines.append(f"    {field_name}: dict | None = None")
            else:
                opt = self._optional_type(field_type)
                lines.append(f"    {field_name}: {opt} = None")
            lines.append("")

    # Error event (always generated)
    lines.append("")
    lines.append("@dataclass")
    error_cls = plan.error_event_class or f"{plan.control_name}ErrorEvent"
    lines.append(f'class {error_cls}(ft.Event["{plan.control_name}"]):')
    lines.append('    """Event fired when an error occurs."""')
    lines.append("")
    lines.append("    method: Optional[str] = None")
    lines.append('    """The method that caused the error."""')
    lines.append("")
    lines.append("    message: Optional[str] = None")
    lines.append('    """The error message."""')
    lines.append("")
    lines.append("    stack_trace: Optional[str] = None")
    lines.append('    """The stack trace, if available."""')
    lines.append("")

    return {"types.py": "\n".join(lines)}

Python Init#

flet_pkg.core.generators.python_init #

Generator for the Python init.py file.

Produces the package's __init__.py with all public exports and __all__ definition.

PythonInitGenerator #

Bases: CodeGenerator

Generates init.py with exports and all.

generate #

generate(plan: GenerationPlan) -> dict[str, str]

Generate __init__.py with public exports and __all__.

Parameters:

Name Type Description Default
plan GenerationPlan

Generation plan produced by the analyzer.

required

Returns:

Type Description
dict[str, str]

Mapping of filename to generated source code.

Source code in src/flet_pkg/core/generators/python_init.py
def generate(self, plan: GenerationPlan) -> dict[str, str]:
    """Generate ``__init__.py`` with public exports and ``__all__``.

    Args:
        plan: Generation plan produced by the analyzer.

    Returns:
        Mapping of filename to generated source code.
    """
    lines: list[str] = []
    all_exports: list[str] = []

    control_snake = plan.control_name_snake or camel_to_snake(plan.control_name)

    # Module docstring
    desc = plan.description or f"{plan.control_name} integration for Flet applications."
    lines.append('"""')
    lines.append(f"{plan.package_name} - {desc}")
    lines.append('"""')
    lines.append("")

    # Main control import
    lines.append(f"from {plan.package_name}.{control_snake} import {plan.control_name}")
    all_exports.append(plan.control_name)

    # Sub-control imports (from the same control module)
    for sub in self._flatten_sub_controls(plan.sub_controls):
        lines.append(f"from {plan.package_name}.{control_snake} import {sub.control_name}")
        all_exports.append(sub.control_name)

    # Sibling widget imports (from separate modules)
    for sibling in plan.sibling_widgets:
        sib_snake = sibling.control_name_snake or camel_to_snake(sibling.control_name)
        lines.append(f"from {plan.package_name}.{sib_snake} import {sibling.control_name}")
        all_exports.append(sibling.control_name)

    # Sub-module imports
    for sub in plan.sub_modules:
        lines.append(f"from {plan.package_name}.{sub.module_name} import {sub.class_name}")
        all_exports.append(sub.class_name)

    # Types imports (always include error event class)
    type_names: list[str] = []
    for enum in plan.enums:
        type_names.append(enum.python_name)
    for event in plan.events:
        type_names.append(event.event_class_name)
    for stub in plan.stub_data_classes:
        type_names.append(stub.python_name)
    # Sub-control event types
    for sub in self._flatten_sub_controls(plan.sub_controls):
        for event in sub.events:
            type_names.append(event.event_class_name)
    # Sibling event types
    for sibling in plan.sibling_widgets:
        for event in sibling.events:
            type_names.append(event.event_class_name)
    # Error event is always generated
    type_names.append(plan.error_event_class or f"{plan.control_name}ErrorEvent")
    type_names = sorted(set(type_names))

    lines.append(f"from {plan.package_name}.types import (")
    for name in type_names:
        lines.append(f"    {name},")
    lines.append(")")
    all_exports.extend(type_names)

    # Console imports (conditional)
    if plan.include_console:
        lines.append(f"from {plan.package_name}.console import DebugConsole, setup_logging")
        all_exports.extend(["DebugConsole", "setup_logging"])

    lines.append("")

    # __all__
    lines.append("__all__ = [")

    # Group: Main control/service
    kind = "service" if plan.base_class == "ft.Service" else "control"
    lines.append(f"    # Main {kind}")
    lines.append(f'    "{plan.control_name}",')

    # Group: Sub-controls
    flat_subs = self._flatten_sub_controls(plan.sub_controls)
    if flat_subs:
        lines.append("    # Sub-controls")
        for sub in flat_subs:
            lines.append(f'    "{sub.control_name}",')

    # Group: Sibling widgets
    if plan.sibling_widgets:
        lines.append("    # Sibling widgets")
        for sibling in plan.sibling_widgets:
            lines.append(f'    "{sibling.control_name}",')

    # Group: Sub-modules
    if plan.sub_modules:
        lines.append("    # Sub-modules")
        for sub in plan.sub_modules:
            lines.append(f'    "{sub.class_name}",')

    # Group: Debug console
    if plan.include_console:
        lines.append("    # Debug console")
        lines.append('    "DebugConsole",')
        lines.append('    "setup_logging",')

    # Group: Types and events
    sub_control_names = {s.control_name for s in flat_subs}
    sibling_names = {s.control_name for s in plan.sibling_widgets}
    sub_module_names = {s.class_name for s in plan.sub_modules}
    console_names = {"DebugConsole", "setup_logging"} if plan.include_console else set()
    already_listed = (
        {plan.control_name}
        | sub_control_names
        | sibling_names
        | sub_module_names
        | console_names
    )
    lines.append("    # Types and events")
    for name in sorted(set(all_exports)):
        if name not in already_listed:
            lines.append(f'    "{name}",')

    lines.append("]")
    lines.append("")

    return {"__init__.py": "\n".join(lines)}

Dart Service#

flet_pkg.core.generators.dart_service #

Generator for the Dart FletService file.

Produces the Dart service (or widget) implementation that handles method dispatch from Python, event listener setup, and real SDK calls.

DartServiceGenerator #

Bases: CodeGenerator

Generates the Dart FletService/FletWidget file.

generate #

generate(plan: GenerationPlan) -> dict[str, str]

Generate Dart service/widget files and optional extension.dart.

Parameters:

Name Type Description Default
plan GenerationPlan

Generation plan produced by the analyzer.

required

Returns:

Type Description
dict[str, str]

Mapping of filename to generated Dart source code.

Source code in src/flet_pkg/core/generators/dart_service.py
def generate(self, plan: GenerationPlan) -> dict[str, str]:
    """Generate Dart service/widget files and optional extension.dart.

    Args:
        plan: Generation plan produced by the analyzer.

    Returns:
        Mapping of filename to generated Dart source code.
    """
    control_snake = plan.control_name_snake or camel_to_snake(plan.control_name)
    service_type = "Service" if plan.base_class == "ft.Service" else "Widget"
    filename = f"{control_snake}_{service_type.lower()}.dart"

    # UI controls use StatefulWidget + LayoutControl pattern
    if service_type == "Widget":
        files: dict[str, str] = {filename: self._generate_ui_control(plan, control_snake)}

        # Generate sibling widget Dart files
        for sibling in plan.sibling_widgets:
            sib_snake = sibling.control_name_snake or camel_to_snake(sibling.control_name)
            sib_file = f"{sib_snake}_widget.dart"
            files[sib_file] = self._generate_sibling_widget(sibling, plan)

        # Generate extension.dart when siblings exist
        if plan.sibling_widgets:
            files["extension.dart"] = self._generate_extension_dart(plan)

        return files

    # Service path — unchanged
    class_name = f"{plan.control_name}{service_type}"
    lines: list[str] = []

    # Imports
    lines.append("import 'dart:convert';")
    lines.append("import 'package:flet/flet.dart';")
    lines.append("import 'package:flutter/foundation.dart';")
    if plan.dart_import:
        lines.append(f"import '{plan.dart_import}';")
    lines.append("")

    # Class
    dart_base = f"Flet{service_type}"
    lines.append(f"/// {plan.control_name} {service_type.lower()} implementation for Flet.")
    lines.append("///")
    lines.append(
        f"/// This {service_type.lower()} handles all communication between the Python SDK"
    )
    lines.append(f"/// and the {plan.flutter_package} Flutter SDK.")
    lines.append(f"class {class_name} extends {dart_base} {{")
    lines.append(f"  {class_name}({{required super.control}});")
    lines.append("")
    lines.append("  bool _initialized = false;")
    lines.append("  bool _listenersSetup = false;")
    lines.append("")

    # init()
    lines.append("  @override")
    lines.append("  void init() {")
    lines.append("    super.init();")
    lines.append("    control.addInvokeMethodListener(_onInvokeMethod);")
    lines.append(f"    _initialize{plan.control_name}();")
    lines.append("  }")
    lines.append("")

    # update()
    lines.append("  @override")
    lines.append("  void update() {")
    lines.append("    super.update();")
    lines.append(f"    _initialize{plan.control_name}();")
    lines.append("  }")
    lines.append("")

    # dispose()
    lines.append("  @override")
    lines.append("  void dispose() {")
    lines.append("    control.removeInvokeMethodListener(_onInvokeMethod);")
    lines.append("    super.dispose();")
    lines.append("  }")
    lines.append("")

    # _initialize method with property reading
    self._render_initialize(lines, plan, class_name)

    # _setupListeners with real event listeners
    self._render_setup_listeners(lines, plan, class_name)

    # Enum parser helpers (if plan uses enums in methods)
    self._render_enum_helpers(lines, plan)

    # _onInvokeMethod with switch dispatch
    self._render_invoke_method(lines, plan)

    # Method implementations with real SDK calls
    all_methods = list(plan.main_methods)
    for sub in plan.sub_modules:
        all_methods.extend(sub.methods)

    for method in all_methods:
        sub_module = self._find_sub_module_for_method(method, plan)
        lines.extend(self._render_dart_method(method, plan, sub_module))
        lines.append("")

    # _handleError
    self._render_handle_error(lines, plan, class_name)

    lines.append("}")
    lines.append("")

    return {filename: "\n".join(lines)}